题意:给定n个点,然后在每个点在一个正方形的上边或者下边的中点,并且所有的正方形等大且不能重叠。求正方形最大的边长是多少。
思路:很明显的二分边长+判定。不过判定要用到2-sat,算是2-sat的入门题吧。
所谓的2-sat,就是对于若干个bool不等式,然后对于会互相干扰(即不能同时成立的),连边处理,然后对于每一块枚举一个点的值,判断是否可行。出现冲突即无解。具体看代码吧。
下面2-sat部分是LRJ的模板,写的挺清晰的。。
1 /* 2 * Author: Yzcstc 3 * Created Time: 2014/3/8 13:40:50 4 * File Name: Poj2296.cpp 5 */ 6 #include<cstdio> 7 #include<iostream> 8 #include<cstring> 9 #include<cstdlib> 10 #include<cmath> 11 #include<algorithm> 12 #include<string> 13 #include<map> 14 #include<set> 15 #include<vector> 16 #include<queue> 17 #include<stack> 18 #include<ctime> 19 #define M0(x) memset(x, 0, sizeof(x)) 20 #define rep(i, a, b) for (int i = (a); i <= (b); ++i) 21 #define red(i, a, b) for (int i = (a); i >= (b); --i) 22 #define PB push_back 23 #define Inf 0x3fffffff 24 #define eps 1e-8 25 #define maxn 500 26 typedef long long LL; 27 using namespace std; 28 struct TwoSat{ 29 int n; 30 vector<int> G[maxn * 2]; 31 bool mark[maxn * 2]; 32 int S[maxn * 2], c; 33 bool dfs(int x){ // 搜索一组解 34 if (mark[x^1]) return false; //出现冲突 35 if (mark[x]) return true; 36 mark[x] = true; 37 S[c++] = x; 38 for (int i = 0; i < G[x].size(); ++i) 39 if (!dfs(G[x][i])) return false; 40 return true; 41 } 42 43 void init(int n){ 44 this->n = n; 45 for (int i = 0; i < 2 * n; ++i) 46 G[i].clear(); 47 memset(mark, 0, sizeof(mark)); 48 } 49 50 void add_clause(int x, int xv, int y, int yv){ 51 x = x * 2 + xv; 52 y = y * 2 + yv; //x,y不能同时存在,那么如果选了y,合法解必定要选x^1 53 G[x^1].push_back(y); 54 G[y^1].push_back(x); 55 } 56 57 bool solve(){ 58 for (int i = 0; i < n * 2; i += 2) 59 if (!mark[i] && !mark[i+1]){ 60 c = 0; 61 if (!dfs(i)){ //枚举2种取值都无解 62 while (c > 0) mark[S[--c]] = false; 63 if (!dfs(i+1)) return false; 64 } 65 } 66 return true; 67 } 68 } Sat; 69 70 int n, X[200], Y[200], T; 71 72 void init(){ 73 scanf("%d", &n); 74 for (int i = 0; i < n; ++i) 75 scanf("%d%d", &X[i], &Y[i]); 76 } 77 78 bool check(int r){ 79 Sat.init(n); 80 for (int i = 0; i < n; ++i) 81 for (int j = i + 1; j < n; ++j) if (i != j){ //分类讨论冲突情况 82 if (Y[i] < Y[j]){ 83 if (Y[j] - Y[i] < r && abs(X[i] - X[j]) < r) Sat.add_clause(i, 0 , j, 0); 84 if (Y[j] - Y[i] < 2 * r && abs(X[i] - X[j]) < r) Sat.add_clause(i, 1 , j, 0); 85 if (Y[j] - Y[i] < r && abs(X[i] - X[j]) < r) Sat.add_clause(i, 1 , j, 1); 86 } 87 if (Y[i] > Y[j]){ 88 if (Y[i] - Y[j] < r && abs(X[i] - X[j]) < r) Sat.add_clause(i, 0 , j, 0); 89 if (Y[i] - Y[j] < 2 * r && abs(X[i] - X[j]) < r) Sat.add_clause(i, 0 , j, 1); 90 if (Y[i] - Y[j] < r && abs(X[i] - X[j]) < r) Sat.add_clause(i, 1 , j, 1); 91 } 92 if (Y[i] == Y[j]){ 93 if (abs(X[i] - X[j]) < r) Sat.add_clause(i, 0 , j, 0); 94 if (abs(X[i] - X[j]) < r) Sat.add_clause(i, 1 , j, 1); 95 } 96 } 97 return Sat.solve(); 98 } 99 100 void solve(){ 101 int l = 0, r = 40000, mid; 102 int cnt = 0, ans = 0; 103 while (l <= r){ //二分答案 104 mid = (l + r) >> 1; 105 if (check(mid)) { ans = mid, l = mid + 1;} 106 else r = mid - 1; 107 } 108 printf("%d ",ans); 109 } 110 111 int main(){ 112 freopen("a.in", "r", stdin); 113 freopen("a.out", "w", stdout); 114 scanf("%d", &T); 115 while (T--){ 116 init(); 117 solve(); 118 } 119 fclose(stdin); fclose(stdout); 120 return 0; 121 }