【二分答案+2-SAT】Now or later UVALive - 3211
题目链接:https://cn.vjudge.net/contest/209473#problem/J
题目大意:
有n架飞机,每架飞机有两个可降落时间点a,b(a<b)(即一架飞机可以选择在时间a降落或者时间b降落),设计一个方案,当n架飞机降落后,相邻两架飞机的最小间隔时间最大。
解题思路:
最小XX最大问题或者最大XX最小问题,很容易就能想到二分的方法,所以如果我们二分答案,问题就转化成了判断“每相邻两架飞机降落时间间隔为x,这个方案是否可行?”。
在这道题里每一架飞机都有两种选择,但是必须且只能选择其中一种。
每架飞机可化为两种状态(选a或者选b),两种状态只选其一,且每架飞机的两种状态互相关联(相隔降落时间)。
这些已经足够让我们想到2-SAT的解法了。
关于2-SAT的介绍:http://www.cnblogs.com/L-Excalibur/p/8504893.html
所以我们就得到了判断方法:对于一个时间间隔x,如果2-sat图像成立,那么就是可行解,反之不可行。
难点转化为建图:
对于二分的答案x,如果两架飞机(P、Q)的某状态相邻间隔时间小于x,那么这两个状态务必不能同时满足,所以如果我强制要求满足P的这个状态,Q就只能满足另一个状态(注意,这里转化成了若p即q的情况了!注意其中的必然关系,若p则必定q),对于Q同理。
我们就得到了一个对称的图,然后就是跑模板,没什么说的。
下边是1102msAC代码:
1 /* by Lstg */ 2 /* 2018-03-05 22:46:35 */ 3 4 #include<stdio.h> 5 #include<string.h> 6 #define MAXN 4100 7 8 bool mark[MAXN],g[MAXN][MAXN]; 9 int stk[MAXN],a[MAXN][2]; 10 11 int top,n; 12 13 int _abs(int x){return x<0?-x:x;} 14 15 bool _dfs(int x){ 16 17 if(mark[x^1])return false; 18 if(mark[x])return true; 19 mark[x]=true; 20 stk[++top]=x; 21 for(int i=2;i<=2*n+1;i++) 22 if(g[x][i]&& !_dfs(i))return false; 23 return true; 24 25 } 26 27 bool _twosat(int x){ 28 29 top=0; 30 if(!_dfs(x)){ 31 while(top) 32 mark[stk[top--]]=false; 33 if(!_dfs(x^1))return false; 34 } 35 return true; 36 } 37 38 39 bool _check(int x){ 40 41 int i,j,k,l; 42 memset(mark,0,sizeof(mark)); 43 memset(g,0,sizeof(g)); 44 for(i=1;i<=n;i++) 45 for(j=i+1;j<=n;j++){ 46 for(k=0;k<=1;k++) 47 for(l=0;l<=1;l++) 48 if(x>_abs(a[i][k]-a[j][l])){//这个绝对值是必要的 49 g[i*2+k][j*2+(l^1)]=true; 50 g[j*2+l][i*2+(k^1)]=true; 51 } 52 } 53 54 for(i=1;i<=n;i++) 55 if(!mark[i*2]&&!mark[i*2+1]) 56 if(!_twosat(2*i))return false; 57 return true; 58 } 59 60 61 62 int main(){ 63 64 int i,l,r,mid; 65 while(scanf("%d",&n)!=EOF){ 66 67 for(i=1;i<=n;i++) 68 scanf("%d%d",&a[i][0],&a[i][1]); 69 l=0;r=10000001; 70 while(l<r){ 71 if(l+1==r)break; 72 mid=(l+r)>>1; 73 if(_check(mid))l=mid; 74 else r=mid; 75 } 76 printf("%d\n",l); 77 } 78 return 0; 79 }