http://www.cnblogs.com/ambition/archive/2011/11/09/Eliminate_the_Conflict.html
题意:
两个人石头剪刀布,一个人的出法是确定的,另一个人的出法有一定约束,某两次要相同或者不同,问你第二个人能否全部都不失败。
思路:
拆成六个点:
石头(R), 非石头(~R)
布(P), 非布(~P)
剪刀(S), 非剪刀(~S)
1. 每次只能三者取一个,那么就是如果出了一个,另外两个就不能出
R->~P, R->~S, P->~R, P->~S, S->~R, S->~P
2. 根据对方的出法,只能出平局和胜局两种出法
比如:如果对方是石头(R),那么只能出R和P,非R即P,非P即R
~R->P, ~P->R
3. 加入约束关系,如果两次必须相同:
R1<->R2, P1<->P2, S1<->S2 均是双向边
如果不同也是一样
R1->~R2, R2->~R1, ......
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 60005 #define M 999999 struct Edge{ int vtx,next; }E[M]; int head[N],size; int dfn[N],low[N],blg[N],step,scc; int stk[N],top; bool ins[N]; void Init(){ memset(head,-1,sizeof(head)); memset(dfn,-1,sizeof(dfn)); memset(ins,false,sizeof(ins)); step=size=0; top=-1; } void Insert(int u,int v){ E[size].vtx=v; E[size].next=head[u]; head[u]=size++; } void Tarjan(int u){ stk[++top]=u; ins[u]=true; dfn[u]=low[u]=step++; for(int i=head[u];~i;i=E[i].next){ int v=E[i].vtx; if(dfn[v]==-1){ Tarjan(v); low[u]=min(low[u],low[v]); }else if(ins[v]){ low[u]=min(low[u],dfn[v]); } } if(low[u]==dfn[u]){ for(int v=-1;v!=u;top--){ v=stk[top]; ins[v]=false; blg[v]=scc; } scc++; } } int main(){ int t,cas=0; scanf("%d",&t); while(t--){ int n,m; scanf("%d%d",&n,&m); /*build*/ Init(); for(int i=0;i<n;i++){ Insert(i*6+0,i*6+3); Insert(i*6+0,i*6+5); Insert(i*6+2,i*6+1); Insert(i*6+2,i*6+5); Insert(i*6+4,i*6+1); Insert(i*6+4,i*6+3); } for(int i=0;i<n;i++){ int v; scanf("%d",&v); if(v==1){ Insert(i*6+3,i*6+0); Insert(i*6+1,i*6+2); }else if(v==2){ Insert(i*6+5,i*6+2); Insert(i*6+3,i*6+4); }else if(v==3){ Insert(i*6+5,i*6+0); Insert(i*6+1,i*6+4); } } for(int i=0;i<m;i++){ int a,b,v; scanf("%d%d%d",&a,&b,&v); a--; b--; if(v){ Insert(a*6+0,b*6+1); Insert(a*6+2,b*6+3); Insert(a*6+4,b*6+5); Insert(b*6+0,a*6+1); Insert(b*6+2,a*6+3); Insert(b*6+4,a*6+5); }else{ Insert(a*6+0,b*6+0); Insert(a*6+2,b*6+2); Insert(a*6+4,b*6+4); Insert(b*6+0,a*6+0); Insert(b*6+2,a*6+2); Insert(b*6+4,a*6+4); } } /*2-SAT*/ for(int i=0;i<n*6;i++){ if(dfn[i]==-1) Tarjan(i); } bool flag=true; for(int i=0;i<n*3;i++){ if(blg[i<<1]==blg[i<<1|1]){ flag=false; break; } } printf("Case #%d: ",++cas); puts(flag?"yes":"no"); } }