题意:两个人玩石头剪刀布,其中一个人知道另一个人会出什么,因此这个人给另一个人提出了一些限制:A、B、K,如果K==0,表示第A局和第B局这两局这个人出的东西必须一样,K==1,表示不一样。给出第一个人会出什么,求第二个人能否保持不败。
思路:用2-SAT可以很好地解决这个问题,这个题要把每一局拆成6的点:出石头,不出石头,出布,不出布,出剪刀,不出剪刀。另外还要满足每一局不能出两样。对于每个限制,如果K==0,则要满足:如果出A局出布(剪刀or石头),B局必须出布(剪刀or石头)……,如果K==1,则要满足第A局和第B局不能出一样的。最后对于每一局,必须出可以平或者赢的拳,最后跑个2-SAT模板就行了~
代码:
#include <iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<set> #include<stack> #include<cmath> #include<vector> #define inf 0x3f3f3f3f #define Inf 0x3FFFFFFFFFFFFFFFLL #define eps 1e-9 #define pi acos(-1.0) using namespace std; typedef long long ll; const int maxn=10000+10; int w[maxn]; struct TwoSAT { int n; vector<int>G[maxn*6]; bool mark[maxn*6]; int S[maxn*6],c; bool dfs(int u) { if(mark[u^1]) return false; if(mark[u]) return true; mark[u]=true; S[c++]=u; for(int i=0;i<G[u].size();++i) { if(!dfs(G[u][i])) return false; } return true; } void Init(int n) { this->n=n; memset(mark,0,sizeof(mark)); for(int i=0;i<n*2;++i) G[i].clear(); } void add_clause(int x,int xval,int y,int yval) { x=x*2+xval; y=y*2+yval; G[x^1].push_back(y); G[y^1].push_back(x); } bool solve() { for(int i=0;i<n*2;i+=2) { if(!mark[i]&&!mark[i+1]) { c=0; if(!dfs(i)) { while(c>0) mark[S[--c]]=false; if(!dfs(i+1)) return false; } } } return true; } }solver; int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int t,n,m,tcase=0; scanf("%d",&t); while(t--) { tcase++; scanf("%d%d",&n,&m); solver.Init(n*3); for(int i=0;i<n;++i) scanf("%d",&w[i]); for(int i=0;i<n;i++) { solver.add_clause(i*3,0,i*3+1,0); solver.add_clause(i*3+1,0,i*3+2,0); solver.add_clause(i*3+2,0,i*3,0); } int a,b,k; for(int i=0;i<m;++i) { scanf("%d%d%d",&a,&b,&k); a--;b--; if(k==0) { a*=3;b*=3; solver.add_clause(a,0,b,1); solver.add_clause(a,1,b,0); solver.add_clause(a+1,0,b+1,1); solver.add_clause(a+1,1,b+1,0); solver.add_clause(a+2,0,b+2,1); solver.add_clause(a+2,1,b+2,0); } else { a*=3;b*=3; solver.add_clause(a,0,b,0); //solver.add_clause(a,1,b,1); solver.add_clause(a+1,0,b+1,0); //solver.add_clause(a+1,1,b+1,1); solver.add_clause(a+2,0,b+2,0); //solver.add_clause(a+2,1,b+2,1); } } for(int i=0;i<n;++i) { a=i*3; if(w[i]==1) { solver.add_clause(a,1,a+1,1); //solver.mark[(a+2)*2]=true; } else if(w[i]==2) { solver.add_clause(a+1,1,a+2,1); //solver.mark[a*2]=true; } else { solver.add_clause(a+2,1,a,1); //solver.mark[(a+1)*2]=true; } } printf("Case #%d: ",tcase); if(solver.solve()) puts("yes"); else puts("no"); } return 0; }