HDU4115-2-SAT
题意
Alice和Bob玩n次剪刀石头布游戏
在这里,1代表石头,2代表布,3代表剪刀
Alice知道Bob每次出什么,为了公平他让Bob制订了m条规则
每条规则是第a轮次和第b轮次Alice必须出相同(或者不同)的手势
问Alice是否可以遵守规则之下每一轮次都不输给Bob
分析
对于bob每次出招,Alice都只能有两种状态,平局或者赢,由此构成2-SAT
如果2-SAT无解说明Alice如果遵循规则则至少要输一次
如果2-SAT有解但是某个解是所有轮次平局,那Alice还能赢吗
这时候我们把(1,2,3)置换成(2,3,1),Alice就美滋滋的n战n胜了
所以如果2-SAT有解,则Alice一定可以赢
其实题意说平局也算Alice赢的啦
如何构图呢
如果要求第a轮和第b轮相同,而a平和b赢不同,则加边(a平,b平),(b赢,a赢)
如果要求第a轮和第b轮不同,而a平和b赢相同,则加边(a平,b平),(b赢,a赢)
貌似只要考虑这两类矛盾就可以(ac)了?
下面的操作是正确的,但是不加也可以ac
如果要求第a轮和第b轮相同,而a_i和a_j相同,则加边(a_i,a_j),(a_j,a_i)
emmm貌似过度分类讨论所有细节有时候不太简洁呢
代码
#include <cstdio> #include <cstring> #define MAX 1000007 #define MAXN 20007 #define MAXM 20007 using namespace std; typedef long long LL; struct Edge{int to,next;}edge[MAXM]; int head[MAXN],tot; int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN]; int Index,top; int scc; bool Instack[MAXN]; int num[MAXN]; void addEdge(int u,int v) { edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++; } void addEdge(int u,int v,int x,int y){ addEdge(u,v); addEdge(x,y); } void Tarjan(int u) { int v; Low[u]=DFN[u]=++Index; Stack[top++]=u; Instack[u]=true; for(int i=head[u];i!=-1;i=edge[i].next){ v=edge[i].to; if(!DFN[v]){ Tarjan(v); if(Low[u]>Low[v])Low[u]=Low[v]; } else if(Instack[v]&&Low[u]>DFN[v]) Low[u]=DFN[v]; } if(Low[u]==DFN[u]){ scc++; do{ v=Stack[--top]; Instack[v]=false; Belong[v]=scc; num[scc]++; }while(v!=u); } } bool solve(int N) { memset(DFN,0,sizeof DFN); memset(Instack,false,sizeof Instack); memset(num,0,sizeof num); Index=scc=top=0; for(int i=1;i<=N;i++) if(!DFN[i])Tarjan(i); int n=N/2; for(int i=1;i<=n;i++){ if(Belong[i]==Belong[i+n])return false; } return true; } void init() { tot=0; memset(head,-1,sizeof head); } int bob[MAXN],cas,n,m,a,b,k,x,beat[4]={0,2,3,1}; int main(){ scanf("%d",&cas); for(int ccc=1;ccc<=cas;ccc++){ init(); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&x); bob[i]=x; bob[i+n]=beat[x]; } for(int i=1;i<=m;i++){ scanf("%d%d%d",&a,&b,&k); if(k==0){ if(bob[a]!=bob[b]){ addEdge(a,b+n,b,a+n); } if(bob[a]!=bob[b+n]){ addEdge(a,b,b+n,a+n); } if(bob[a+n]!=bob[b]){ addEdge(a+n,b+n,b,a); } if(bob[a+n]!=bob[b+n]){ addEdge(a+n,b,b+n,a); } } else{ if(bob[a]==bob[b]){ addEdge(a,b+n,b,a+n); } if(bob[a]==bob[b+n]){ addEdge(a,b,b+n,a+n); } if(bob[a+n]==bob[b]){ addEdge(a+n,b+n,b,a); } if(bob[a+n]==bob[b+n]){ addEdge(a+n,b,b+n,a); } } } printf("Case #%d: ",ccc); printf(solve(n*2)?"yes\n":"no\n"); } return 0; }