每一局alice要么与Bob平手,要么赢Bob,二取一,为2SAT问题,而不是锤子剪刀布3SAT。
对于m次要求,不管是same还是different,都分成三种情况,挺好想的2SAT。
#include <cstdio> #include <cstring> #include <iostream> using namespace std; const int NN=25000; const int MM=100000; int n,m,en,head[NN],a[NN][2]; struct Edge{ int v,next; Edge() {} Edge(int _v,int _next): v(_v),next(_next) {} } e[MM]; void add(int u,int v) { e[en]=Edge(v,head[u]); head[u]=en++; } int top,vn,bn,dfn[NN],low[NN],belong[NN],stack[NN]; bool instack[NN]; void tarjan(int u) { dfn[u]=low[u]=++vn; stack[++top]=u; instack[u]=1; int v; for (int i=head[u]; i!=-1; i=e[i].next) { v=e[i].v; if (!dfn[v]) { tarjan(v); if (low[v]<low[u]) low[u]=low[v]; } else if (instack[v] && dfn[v]<low[u]) low[u]=dfn[v]; } if (low[u]==dfn[u]) { bn++; do { v=stack[top--]; instack[v]=0; belong[v]=bn; }while (v!=u); } } bool two_sat() { top=vn=bn=0; for (int i=1; i<=2*n; i++) dfn[i]=0,instack[i]=0; for (int i=1; i<=2*n; i++) if (!dfn[i]) tarjan(i); for (int i=1; i<=n; i++) if (belong[i]==belong[i+n]) return 0; return 1; } int main() { int T,b,x,y,z,cas=0; scanf("%d",&T); while (T--) { en=0; memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); for (int i=1; i<=n; i++) { scanf("%d",&b); b--; a[i][0]=b; a[i][1]=(b+1)%3; } for (int i=1; i<=m; i++) { scanf("%d%d%d",&x,&y,&z); if (z==0) { if (a[x][0]==a[y][0]) { add(x,y); add(x+n,y+n); add(y,x); add(y+n,x+n); } if (a[x][0]==a[y][1]) { add(x,y+n); add(x+n,x); add(y,y+n); add(y+n,x); } if (a[x][1]==a[y][0]) { add(x,x+n); add(x+n,y); add(y,x+n); add(y+n,y); } } else { if (a[x][0]==a[y][0]) { add(x,y+n); add(x+n,y); add(y,x+n); add(y+n,x); } if (a[x][0]==a[y][1]) { add(x,y); add(y+n,x+n); } if (a[x][1]==a[y][0]) { add(x+n,y+n); add(y,x); } } } printf("Case #%d: ",++cas); if (two_sat()) puts("yes"); else puts("no"); } return 0; }