POJ 2-sat六题最后一题
http://blog.sina.com.cn/s/blog_64675f540100k2xf.html
poj 六道2-sat最后一题第六题:
题目描述:有n个农场,每个农场有坐标x,y。
有两个集合点s1和s2(也有坐标),每个农场必须连接其中的一个(有且仅有一个)。
然后有A个条件,每个条件a,b表示a农场不能和b农场连接在一个集合点。
然后再有B个条件,每个条件a,b表示a农场必须和b农场连接在一个集合点。
问你,在各种合法的连接情况中,任何两个农场间的距离的最大值的最小值是多少。
解题报告:
每个农场i分成两个点,i和i + n,前面表示连接左侧集合点,后面的表示连接右侧集合点。
对于条件A中的ab,连接
<a, b + n> <a + n, b> <b, a + n> <b + n, a>
这样就保证了ab不再一个集合点。同理,B条件也很好写。
然后就是用二分枚举答案(距离的最大值)。
对于每一次枚举的答案key,枚举任意两个农场a,b, 如果他俩的4种距离(a->s1->s1>b, a->s2->s2->b, a->s1->s2->b, a->s2->s1->b)有大于key的,就加入判定条件,不能这样连接。
// File Name: 2749.cpp // Author: zlbing // Created Time: 2013/2/5 21:18:58 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include <cmath> using namespace std; #define MAXN 1000 struct TwoSAT{ int n; vector<int>G[MAXN*2]; bool mark[MAXN*2]; stack<int>S; bool dfs(int x) { if(mark[x^1])return false; if(mark[x])return true; mark[x]=true; S.push(x); for(int i=0;i<G[x].size();i++) { int v=G[x][i]; if(!dfs(v))return false; } return true; } void init(int _n) { n=_n; for(int i=0;i<2*n;i++) G[i].clear(); memset(mark,0,sizeof(mark)); } void add_clause(int x,int y) { G[x].push_back(y); } bool solve() { for(int i=0;i<2*n;i=i+2) { if(!mark[i]&&!mark[i+1]){ while(!S.empty()) { S.pop(); } if(!dfs(i)) { while(!S.empty()) { mark[S.top()]=false; S.pop(); } if(!dfs(i+1))return false; } } } // for(int i=0;i<2*n;i++) // if(mark[i])printf("%d ",T[i/2][i%2]); // printf("\n"); return true; } }; int N,A,B; int s[2][2]; int d[MAXN][2]; int d1[MAXN][2]; int d2[MAXN][2]; int AlenB; TwoSAT solver; int count(int i,int j) { return abs(d[i][0]-s[j][0])+abs(d[i][1]-s[j][1]); } bool test(int M) { solver.init(N); for(int i=0;i<A;i++) { solver.add_clause(d1[i][0]*2,d1[i][1]*2+1); solver.add_clause(d1[i][0]*2+1,d1[i][1]*2); solver.add_clause(d1[i][1]*2+1,d1[i][0]*2); solver.add_clause(d1[i][1]*2,d1[i][0]*2+1); } for(int i=0;i<B;i++) { solver.add_clause(d2[i][0]*2,d2[i][1]*2); solver.add_clause(d2[i][0]*2+1,d2[i][1]*2+1); solver.add_clause(d2[i][1]*2,d2[i][0]*2); solver.add_clause(d2[i][1]*2+1,d2[i][0]*2+1); } for(int i=0;i<N;i++) for(int j=i+1;j<N;j++) { if(count(i,0)+count(j,0)>M) { solver.add_clause(i*2,j*2+1); solver.add_clause(j*2,i*2+1); } if(count(i,1)+count(j,1)>M) { solver.add_clause(i*2+1,j*2); solver.add_clause(j*2+1,i*2); } if(count(i,1)+count(j,0)+AlenB>M) { solver.add_clause(i*2+1,j*2+1); solver.add_clause(j*2,i*2); } if(count(i,0)+count(j,1)+AlenB>M) { solver.add_clause(i*2,j*2); solver.add_clause(j*2+1,i*2+1); } } if(solver.solve())return true; else return false; } #define MAXN 4000000 int main(){ while(~scanf("%d%d%d",&N,&A,&B)) { scanf("%d%d%d%d",&s[0][0],&s[0][1],&s[1][0],&s[1][1]); AlenB=abs(s[0][0]-s[1][0])+abs(s[0][1]-s[1][1]); for(int i=0;i<N;i++) scanf("%d%d",&d[i][0],&d[i][1]); int a,b; for(int i=0;i<A;i++) { scanf("%d%d",&a,&b); d1[i][0]=--a; d1[i][1]=--b; } for(int i=0;i<B;i++) { scanf("%d%d",&a,&b); d2[i][0]=--a; d2[i][1]=--b; } int L=0,R=MAXN; while(L<R) { int mid=L+(R-L)/2; if(test(mid)){ R=mid; } else L=mid+1; } if(R==MAXN)printf("-1\n"); else printf("%d\n",R); } return 0; }