算法指南
就是从飞机早着陆还晚着路两种状态可以组合成一个点,类似2--sat把一个点划分成两个点来表示状态,再二分时间,如果小于时间则可以转化成相应的约数条件:“xi或xj为假”这样的条件。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<queue> 5 #include<stack> 6 #include<bits/stdc++.h> 7 using namespace std; 8 #define LL long long 9 const int maxn = 2000 + 10; 10 //模板 11 struct TwoSAT { 12 int n; 13 vector<int> G[maxn*2]; 14 bool mark[maxn*2]; 15 int S[maxn*2], c; 16 17 bool dfs(int x) { 18 if (mark[x^1]) return false; 19 if (mark[x]) return true; 20 mark[x] = true; 21 S[c++] = x; 22 for (int i = 0; i <(int)G[x].size(); i++) 23 if (!dfs(G[x][i])) return false; 24 return true; 25 } 26 27 void init(int n) { 28 this->n = n; 29 for (int i = 0; i < n*2; i++) G[i].clear(); 30 memset(mark, 0, sizeof(mark)); 31 } 32 33 // x = xval or y = yval 34 void add_clause(int x, int xval, int y, int yval) { 35 x = x * 2 + xval; 36 y = y * 2 + yval; 37 G[x^1].push_back(y); 38 G[y^1].push_back(x); 39 } 40 41 bool solve() { 42 for(int i = 0; i < n*2; i += 2) 43 if(!mark[i] && !mark[i+1]) { 44 c = 0; 45 if(!dfs(i)) { 46 while(c > 0) mark[S[--c]] = false; 47 if(!dfs(i+1)) return false; 48 } 49 } 50 return true; 51 } 52 }; 53 54 TwoSAT solver; 55 56 int n, T[maxn][2]; 57 58 bool test(int diff) { 59 solver.init(n); 60 for(int i = 0; i < n; i++) for(int a = 0; a < 2; a++) 61 for(int j = i+1; j < n; j++) for(int b = 0; b < 2; b++) 62 if(abs(T[i][a] - T[j][b]) < diff) //只有小于diff的时候才满足布尔关系,详见算法指南 63 solver.add_clause(i, a^1, j, b^1);//i,j之间建立边,注意早飞还是晚飞状态 64 return solver.solve(); 65 } 66 67 int main() { 68 while(scanf("%d", &n) == 1 && n) { 69 int L = 0, R = 0; 70 for(int i = 0; i < n; i++) for(int a = 0; a < 2; a++) { 71 scanf("%d", &T[i][a]); 72 R = max(R, T[i][a]); 73 } 74 //二分时间,如果大于中间值,则证明还可以增大时间 75 while(L < R) { 76 int M = L + (R-L+1)/2; 77 if(test(M)) L = M; 78 else R = M-1; 79 } 80 printf("%d ", L); 81 } 82 return 0; 83 }