UVALive-3211 Now or later (2-SAT+二分)
题目大意:有n架飞机,每架飞机有两个可选择的着陆时间,并且每架飞机都必须要选一个时间着陆。为了安全考虑,要求两架飞机的最小着陆时间差最大,找出这个最大值。
题目分析:有“最小值的最大值”这样的字眼,用二分。二分枚举这个最小时间差的最大值p,则问题变成了这样的:有n个只有两个元素的集合,每个元素代表一个时间点,现在要从这些集合中选出n个(一个集合中必须选出一个)元素构成新的集合,使得新集合中任意两点之间的差值都不小于p,找到满足条件的最大的p。
如果两个不同集合中的两个元素(一个集合中一个)之间的差值(绝对值,也就是时间差)小于p,那么这两个元素之间便有矛盾,不能同时被选。例如:设x1、x2为同一个集合中的元素,y1、y2为另一个集合中的元素,如果x1与y1之差小于p,那么如果选了x1就必须选y2,反过来,选了y1就必须选x2。这样就是2-SAT模型了。只需找出使得这个2-SAT有解的最大p即可。
代码如下:
# include<iostream> # include<cstdio> # include<vector> # include<cstring> # include<algorithm> using namespace std; const int maxn=2005; int n,cnt,S[maxn*2],mark[maxn*2],Table[maxn][2]; vector<int>G[maxn*2]; void add(int x,int a,int y,int b) { x=x*2+a; y=y*2+b; G[x^1].push_back(y); G[y^1].push_back(x); } bool dfs(int u) { if(mark[u^1]) return false; if(mark[u]) return true; mark[u]=1; S[cnt++]=u; for(int i=0;i<G[u].size();++i) if(!dfs(G[u][i])) return false; return true; } bool judge(int M) { for(int i=0;i<2*n;++i) G[i].clear(); memset(mark,0,sizeof(mark)); for(int i=0;i<n;++i) for(int a=0;a<2;++a) for(int j=i+1;j<n;++j) for(int b=0;b<2;++b) if(abs(Table[i][a]-Table[j][b])<M) add(i,a^1,j,b^1); for(int i=0;i<2*n;i+=2){ if(!mark[i]&&!mark[i+1]){ cnt=0; if(!dfs(i)){ while(cnt>0) mark[S[--cnt]]=0; if(!dfs(i+1)) return false; } } } return true; } int main() { int L,R; while(scanf("%d",&n)!=EOF) { L=R=0; for(int i=0;i<n;++i){ scanf("%d%d",&Table[i][0],&Table[i][1]); R=max(R,max(Table[i][0],Table[i][1])); } while(L<R) { int M=L+(R-L+1)/2; if(judge(M)){ L=M; }else R=M-1; } printf("%d\n",L); } return 0; }