POJ 2296 Map Labeler(2-SAT)
http://poj.org/problem?id=2296
题意:
平面上有n个给定坐标且不重叠的点,现在每个点要画一个大小相同的正方形(各边平行于坐标轴),对于每个点来说,该点只能在该正方形的上边的中点或下边的中点.现在的问题是,该正方形最大边长能为多少(整数),且各个点的正方形还能不重叠?
分析:
其实每个点只有两种选择,朝上画或者朝下画.对于任意两个点a和b来说,假设a=0表示朝上画,a=1表示朝下画.那么如果对于固定正方形长度mid来说, a朝上且b朝上时,正方形如果重叠,那么可以推出边: a = 0 -> b=1 且b=0 -> a=1. 依次类推.
假设点都存在结构体s[n]中,如果abs(s[i].x-s[j].x)>= mid ,则可以随便放.(i取0表示上放,i取1表示下放)
否则abs(s[i].x-s[j].x)<mid时:
1.abs(s[i].y-s[j].y)==0,则必须一个放上,一个放下. add(i,0,j,1) add(i,1,j,0), add(j,0,i,1), add(j,1,i,0)
2.0<abs(s[i].y-s[j].y)<mid, 则必须上面的点上放,下面的点下放. 假设i点在上,j点在下(即 s[i].y > s[j].y) ,则add(i,1,i,0) 且add(j,0,j,1)
3.mid<=abs(s[i].y-s[j].y)<2*mid,则只有一种情况不合法,即上面的点往下放且下面的点往上放. 假设i点在上,则:
add(i,1,j,1) 且 add(j,0,i,0)
AC代码:
#include<cstdio> #include<cstring> #include<vector> #include<algorithm> #include<cmath> using namespace std; const int maxn= 100+10; int n; //点个数 struct TwoSAT { int n; vector<int> G[maxn*2]; int S[maxn*2],c; bool mark[maxn*2]; 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)); } void add_clause(int x,int xval,int y,int yval) { x=x*2+xval; y=y*2+yval; G[x].push_back(y); } bool solve() { for(int i=0;i<2*n;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; } }TS; struct Node { int x,y; }s[maxn]; bool ok(int mid) { TS.init(n); for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) if(abs(s[i].x-s[j].x) < mid) { if(s[i].y==s[j].y) { TS.add_clause(i,0,j,1); TS.add_clause(i,1,j,0); TS.add_clause(j,0,i,1); TS.add_clause(j,1,i,0); } else if( abs(s[i].y-s[j].y) < mid ) { if(s[i].y > s[j].y) { TS.add_clause(i,1,i,0); TS.add_clause(j,0,j,1); } else { TS.add_clause(i,0,i,1); TS.add_clause(j,1,j,0); } } else if( abs(s[i].y-s[j].y) < 2*mid ) { if(s[i].y > s[j].y) { TS.add_clause(i,1,j,1); TS.add_clause(j,0,i,0); } else { TS.add_clause(j,1,i,1); TS.add_clause(i,0,j,0); } } } return TS.solve(); } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%d%d",&s[i].x,&s[i].y); } int L=0,R=20000+1; while(R>L) { int mid = L+(R-L+1)/2; if(ok(mid)) L=mid; else R=mid-1; } printf("%d\n",L); } return 0; }