2-sat系列(一) POJ 2723 Get Luffy Out
2012-12-05 12:48
399 查看
题意:有2n把钥匙,分成2组,给你每组的钥匙信息,并且每组的钥匙只能用一个。m个门,每个门有2个锁,只要打开一个锁这个门就开了。(顺序遇见m个门)问你最多能够打开多少个门。
建边方式:(需要建2类边,对于每组钥匙(A,B),增加点对(A',B'))
1:n 对钥匙中,A 和 B 只能选择一把,用点A 默示选择钥匙 A ,用 A’ 默示不选择(同理用点B 和B‘ 默示钥匙 B 的选择关系),建边(A -> B‘)默示用钥匙 A 就不用钥匙 B ;还有(B -> A')默示用 B 就不用A。
2:m 道门,每对门都有两把钥匙可以开,假设是A和B ,可能的选择是(用A不消B)或者(用B 不消A),按照这个关系建边(B' -> A),(A’ -> B)
建完边后用2分方法即可求出最多能达到第几扇门
2-sat的题目建边是关键,而2-sat建边的原理就是找2个不相容点再进行建边
为什么对门上钥匙建边的时候只能是(A'->B),而不能是(A->B')?
因为建边的时候要求是2个不相容的点对之间建边,而(A,B)不是不相容点对,(A',B')才是不相容点对,不相容点对的意思就是说2个条件不能同时存在,而A,B是可以同时存在的,用A,B同时打开了门上的2把锁,门还是照样能开,相容。而(A',B')表示既不用A钥匙也不用B钥匙,这种情况下门是不能打开的,所以这2个点不能同时存在,同时存在就打不开门,所以为不相容点对,而在建边的时候,每建一条边,如(X->Y)表示选择X后必须选择Y,所以(A'->B)则表示不用A钥匙则必须用B钥匙来开,(B'->A)表示不用B钥匙则必须用A钥匙来。
关于建边的一点点总结:
(1)必须要在不相容点对之间建边,如上面的(A',B'),这2个条件同时存在问题就不能解决,就像这题中的如果2把钥匙都不用,则门肯定打不开
(2)建一条边看下,前面是不是一定能推到后面,像本题中的(A'->B)不用A钥匙则必须要用B钥匙,别无选择,不然门就打不开,而(A->B')这种建边则表示用了A钥匙则一定不能用B钥匙,我可以A,B钥匙同时用,如(A->B),前面不一定能推到后面,所以不可行
建立反向图-->拓扑排序(着色)-->输出结果
结果显示:通过第一扇门需要钥匙0和钥匙1,通过前2扇门只要钥匙0,通过前3扇门只要钥匙0和4......
根据结果也可以想想你建图的思路是否正确!
贴下显示结果源代码,技术不够,写的代码比较长,嘿嘿~~~
建边方式:(需要建2类边,对于每组钥匙(A,B),增加点对(A',B'))
1:n 对钥匙中,A 和 B 只能选择一把,用点A 默示选择钥匙 A ,用 A’ 默示不选择(同理用点B 和B‘ 默示钥匙 B 的选择关系),建边(A -> B‘)默示用钥匙 A 就不用钥匙 B ;还有(B -> A')默示用 B 就不用A。
2:m 道门,每对门都有两把钥匙可以开,假设是A和B ,可能的选择是(用A不消B)或者(用B 不消A),按照这个关系建边(B' -> A),(A’ -> B)
建完边后用2分方法即可求出最多能达到第几扇门
2-sat的题目建边是关键,而2-sat建边的原理就是找2个不相容点再进行建边
为什么对门上钥匙建边的时候只能是(A'->B),而不能是(A->B')?
因为建边的时候要求是2个不相容的点对之间建边,而(A,B)不是不相容点对,(A',B')才是不相容点对,不相容点对的意思就是说2个条件不能同时存在,而A,B是可以同时存在的,用A,B同时打开了门上的2把锁,门还是照样能开,相容。而(A',B')表示既不用A钥匙也不用B钥匙,这种情况下门是不能打开的,所以这2个点不能同时存在,同时存在就打不开门,所以为不相容点对,而在建边的时候,每建一条边,如(X->Y)表示选择X后必须选择Y,所以(A'->B)则表示不用A钥匙则必须用B钥匙来开,(B'->A)表示不用B钥匙则必须用A钥匙来。
关于建边的一点点总结:
(1)必须要在不相容点对之间建边,如上面的(A',B'),这2个条件同时存在问题就不能解决,就像这题中的如果2把钥匙都不用,则门肯定打不开
(2)建一条边看下,前面是不是一定能推到后面,像本题中的(A'->B)不用A钥匙则必须要用B钥匙,别无选择,不然门就打不开,而(A->B')这种建边则表示用了A钥匙则一定不能用B钥匙,我可以A,B钥匙同时用,如(A->B),前面不一定能推到后面,所以不可行
源代码: # include<cstdio> # include<cstring> # include<vector> # include<stack> using namespace std; # define N 10000 int dfn ,low ,instack ,belong ,now,cnt,n,m; stack<int> sta; vector<int> vec ; struct node { int x; int y; }p ,q ; void tarjan(int v) { int i,u,size; dfn[v]=low[v]=++now; sta.push(v); instack[v]=1; size=vec[v].size(); for(i=0;i<size;i++) { u=vec[v][i]; if(!dfn[u]) { tarjan(u); low[v]=min(low[v],low[u]); } else if(instack[u]) low[v]=min(low[v],dfn[u]); } if(dfn[v]==low[v]) { cnt++; while(!sta.empty()) { u=sta.top(); sta.pop(); instack[u]=0; belong[u]=cnt; if(u==v) break; } } } int solve(int mid) { int i; for(i=0;i<4*n;i++) vec[i].clear(); now=cnt=0; memset(instack,0,sizeof(instack)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(belong,0,sizeof(belong)); for(i=0;i<n;i++) { vec[2*p[i].x].push_back(2*p[i].y+1); vec[2*p[i].y].push_back(2*p[i].x+1); } for(i=0;i<mid;i++) { vec[2*q[i].x+1].push_back(2*q[i].y); vec[2*q[i].y+1].push_back(2*q[i].x); } for(i=0;i<4*n;i++) if(!dfn[i]) tarjan(i); for(i=0;i<2*n;i+=2) if(belong[i]==belong[i+1]) return 0; return 1; } int ans() { int l=0,r=m,mid,ans; while(l<=r) { mid=(l+r)>>1; if(solve(mid)) { ans=mid; l=mid+1; } else r=mid-1; } return ans; } int main() { int i; while(scanf("%d%d",&n,&m)!=EOF&&(n+m)) { for(i=0;i<n;i++) scanf("%d%d",&p[i].x,&p[i].y); for(i=0;i<m;i++) scanf("%d%d",&q[i].x,&q[i].y); printf("%d\n",ans()); } return 0; }最后,我们再增加点步骤看看经过经过前面几道门分别需要哪些钥匙,即看看最后的结果
建立反向图-->拓扑排序(着色)-->输出结果
结果显示:通过第一扇门需要钥匙0和钥匙1,通过前2扇门只要钥匙0,通过前3扇门只要钥匙0和4......
根据结果也可以想想你建图的思路是否正确!
贴下显示结果源代码,技术不够,写的代码比较长,嘿嘿~~~
# include<cstdio> # include<cstring> # include<vector> # include<stack> # include<queue> using namespace std; # define N 10000 int dfn ,low ,instack ,belong ,color ,in ,opp ,now,cnt,n,m; stack<int> sta; vector<int> vec ,dag ; queue<int> que; struct node { int x; int y; }p ,q ; void tarjan(int v) { int i,u,size; dfn[v]=low[v]=++now; sta.push(v); instack[v]=1; size=vec[v].size(); for(i=0;i<size;i++) { u=vec[v][i]; if(!dfn[u]) { tarjan(u); low[v]=min(low[v],low[u]); } else if(instack[u]) low[v]=min(low[v],dfn[u]); } if(dfn[v]==low[v]) { cnt++; while(!sta.empty()) { u=sta.top(); sta.pop(); instack[u]=0; belong[u]=cnt; if(u==v) break; } } } void buliddag() //建立反向图 { int i,v,u; for(v=0;v<4*n;v++) { for(i=0;i<vec[v].size();i++) { u=vec[v][i]; if(belong[u]!=belong[v]) { dag[belong[u]].push_back(belong[v]); in[belong[v]]++; } } } } void topsort() //拓扑排序,着色 { int i,v,u; for(i=1;i<=cnt;i++) if(in[i]==0) que.push(i); while(!que.empty()) { u=que.front(); que.pop(); if(!color[u]) { color[u]=1; color[opp[u]]=2; } for(i=0;i<dag[u].size();i++) { v=dag[u][i]; in[v]--; if(in[v]==0) que.push(v); } } } int solve(int mid) { int i; for(i=0;i<4*n;i++) { vec[i].clear(); dag[i].clear(); } now=cnt=0; memset(instack,0,sizeof(instack)); memset(color,0,sizeof(color)); memset(in,0,sizeof(in)); memset(opp,0,sizeof(opp)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(belong,0,sizeof(belong)); for(i=0;i<n;i++) { vec[2*p[i].x].push_back(2*p[i].y+1); vec[2*p[i].y].push_back(2*p[i].x+1); } for(i=0;i<mid;i++) { vec[2*q[i].x+1].push_back(2*q[i].y); vec[2*q[i].y+1].push_back(2*q[i].x); } for(i=0;i<4*n;i++) if(!dfn[i]) tarjan(i); for(i=0;i<4*n;i+=2) { if(belong[i]==belong[i+1]) { printf("The %d door can't go on!\n",mid); return 0; } else { opp[belong[i]]=belong[i+1]; opp[belong[i+1]]=belong[i]; } } buliddag(); topsort(); printf("Pass the %d doors,you should use: ",mid); for(i=0;i<4*n;i+=2) { if(color[belong[i]]==1) printf("key(%d) ",i/2); } printf("\n"); return 1; } int ans() { int l=0,r=m,mid,ans; while(l<=r) { mid=(l+r)>>1; if(solve(mid)) { ans=mid; l=mid+1; } else r=mid-1; } return ans; } int main() { int i; while(scanf("%d%d",&n,&m)!=EOF&&(n+m)) { for(i=0;i<n;i++) scanf("%d%d",&p[i].x,&p[i].y); for(i=0;i<m;i++) scanf("%d%d",&q[i].x,&q[i].y); for(i=1;i<=m;i++) if(!solve(i)) break; // printf("%d\n",ans()); } return 0; }
相关文章推荐
- POJ 2723 Get Luffy Out(2-SAT)
- poj2723 Get Luffy Out (二分+2-SAT)
- |poj 2723|2-SAT|二分|Get Luffy Out
- POJ 2723 Get Luffy Out(2-SAT)
- POJ 2723 Get Luffy Out(2-SAT)
- POJ2723_Get Luffy Out_二分&&2-sat
- Poj 2723 Get Luffy Out【2-SAT---------Tarjan强连通】
- POJ 2723 Get Luffy Out(2-SAT)
- 【HDU】1816 Get Luffy Out * &【POJ】2723 Get Luffy Out 【2-sat】
- POJ 2723 Get Luffy Out 二分 + 2-sat
- poj 2723 Get Luffy Out 2-sat
- Get Luffy Out (poj 2723 二分+2-SAT)
- POJ 2723 Get Luffy Out 2-SAT&&二分搜索
- 2-sat->poj 2723 Get Luffy Out
- Get Luffy Out poj 2723 Tarjan+2-SAT
- POJ 2723 Get Luffy Out (2-sat)
- POJ 2723 Get Luffy Out 二分 2-SAT
- POJ2723-Get Luffy Out(2-SAT)
- POJ 2723 Get Luffy Out 二分 2-SAT
- poj 2723 Get Luffy Out(2-sat)