题目链接:http://vjudge.net/contest/142615#problem/A
题意:n架飞机,每架可选择两个着落时间。安排一个着陆时间表,使得着陆间隔的最小值最大。
分析:
最小值最大,采用二分法,时间间隔最大不超过最晚的一个时间,对于每个时间间隔来说,在此间隔要求下,建立 2-SAT图(两者只能满足其一);建好图后,从一个点出发,把这种只能满足两者其一的点集(2-SAT图)DFS,先满足一个点的一个状态,要是失败搜索,就换一个状态。直到整个图搜索完毕。
如果2-SAT成功搜索,那么,这个时间间隔是否可以更短,二分来了!
#include <bits/stdc++.h> using namespace std; const int maxn = 2000 + 10; int n; int T[maxn][2]; struct TwoSAT { int n; vector<int> G[maxn*2]; bool mark[maxn*2]; int S[maxn*2], c; bool dfs(int x) { if (mark[x^1]) return false; if (mark[x]) return true; mark[x] = true; S[c++] = x; for (int i = 0; i < G[x].size(); i++) if (!dfs(G[x][i])) return false; return true; } void init(int n) { this->n = n; for (int i = 0; i < n*2; i++) G[i].clear(); memset(mark, 0, sizeof(mark)); } // x = xval or y = yval void add_clause(int x, int xval, int y, int yval) { x = x * 2 + xval; y = y * 2 + yval; G[x^1].push_back(y); G[y^1].push_back(x); } bool solve() { for(int i = 0; i < n*2; i += 2) if(!mark[i] && !mark[i+1]) { c = 0; if(!dfs(i)) { while(c > 0) mark[S[--c]] = false; if(!dfs(i+1)) return false; } } return true; } }; TwoSAT solver; bool test(int diff) { solver.init(n); 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(T[i][a]-T[j][b])<diff) // 两者不能同时满足 { solver.add_clause(i,a^1,j,b^1); // (i,a,j,b) } } } } } return solver.solve(); } int main() { while(scanf("%d",&n)!=EOF) { int L = 0,R=0; for(int i=0; i<n; i++) { for(int a=0; a<2; a++) { scanf("%d",&T[i][a]); R = max(R,T[i][a]); } } while(L<R) { int M = L + (R-L+1)/2; if(test(M)) L = M; else R = M-1; } printf("%d ",L); } return 0; }