题意:
有一个地图...地图上有N个city...每个city是都是一个边长相同的平行于x/y轴的正方形..现在给了每个city的一个点.这个点可能是正方形上边的中点,也可能是下边的中点..每个city的区域不能有交集(边可以重合)..问正方形的边最长可以是多少..
题解:
很明显的二分查找+2-sat判断....关键就是如何建图...先将所有city按照x从小到大排序..判断冲突的前提两者横坐标之差小于所二分的长度M..那么就只要考虑纵坐标了..分为两个大方向...两个点之间的距离小于M...两个点之间的距离小于2*M...而这里必须要注意一个特殊的情况..两个点的纵坐标相同.拿出来单独讨论..
Program:
#include<iostream> #include<stdio.h> #include<cmath> #include<queue> #include<stack> #include<string.h> #include<map> #include<set> #include<algorithm> #define oo 1000000007 #define MAXN 20005<<1 #define MAXM 100000<<2 #define ll long long using namespace std; struct city { int x,y; bool operator <(city a) const { return x<a.x; } }C[MAXN]; struct node { int y,next; }line[MAXM]; int Lnum,_next[MAXN],dfn[MAXN],low[MAXN],tp[MAXN],tpnum,DfsIndex; bool instack[MAXN]; stack<int> mystack; void addline(int x,int y) { line[++Lnum].next=_next[x],_next[x]=Lnum,line[Lnum].y=y; } void tarjan(int x) { instack[x]=true,mystack.push(x); dfn[x]=low[x]=++DfsIndex; for (int k=_next[x];k;k=line[k].next) { int y=line[k].y; if (!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); }else if (instack[y]) low[x]=min(low[x],dfn[y]); } if (low[x]==dfn[x]) { tpnum++; do { x=mystack.top(); mystack.pop(); instack[x]=false; tp[x]=tpnum; }while (low[x]!=dfn[x]); } } bool _2sat(int N,int M) { int i,j; Lnum=0,memset(_next,0,sizeof(_next)); for (i=0;i<N;i++) // i<<1上方 i<<1|1 下方 for (j=i+1;j<N;j++) if (C[j].x-C[i].x<M && abs(C[j].y-C[i].y)<(M<<1)) { if (abs(C[j].y-C[i].y)<M) { if (C[j].y==C[i].y) { addline(i<<1,j<<1|1),addline(i<<1|1,j<<1); addline(j<<1,i<<1|1),addline(j<<1|1,i<<1); }else if (C[j].y>C[i].y) addline(j<<1|1,j<<1),addline(i<<1,i<<1|1); else addline(i<<1|1,i<<1),addline(j<<1,j<<1|1); }else if (abs(C[j].y-C[i].y)<(M<<1)) { if (C[j].y>C[i].y) addline(j<<1|1,i<<1|1),addline(i<<1,j<<1); else addline(i<<1|1,j<<1|1),addline(j<<1,i<<1); } } memset(dfn,0,sizeof(dfn)); memset(instack,false,sizeof(instack)); while (!mystack.empty()) mystack.pop(); DfsIndex=tpnum=0; for (i=0;i<(N<<1);i++) if (!dfn[i]) tarjan(i); for (i=0;i<N;i++) if (tp[i<<1]==tp[i<<1|1]) return false; return true; } int main() { int cases,N,i; scanf("%d",&cases); while (cases--) { scanf("%d",&N); for (i=0;i<N;i++) scanf("%d%d",&C[i].x,&C[i].y); sort(C,C+N); int l=-1,r=oo,mid; while (r-l>1) { mid=l+r>>1; if (_2sat(N,mid)) l=mid; else r=mid; } printf("%d\n",l); } return 0; }