坑爹:
看到各种冲突,当然第一反映是2-sat,但是这有三种情况啊,貌似不能满足布尔型约束吧。。。gg吧, 没法做。。。
反思:
传统2-sat是,i拆为两个节点,为真对应i节点,为假对应i+n节点。这个题有三种不同的bool变量可以将每个点拆成6个点。
石头:i*6+0 | i*6+1;
剪刀:i*6+2 | i*6+3;
布: i*6+4 | i*6+5.
这样就能轻松解决各种约束了。。。
#include<algorithm> #include<iostream> #include<cstring> #include<fstream> #include<sstream> #include<vector> #include<string> #include<cstdio> #include<bitset> #include<queue> #include<stack> #include<cmath> #include<map> #include<set> #define FF(i, a, b) for(int i=a; i<b; i++) #define FD(i, a, b) for(int i=a; i>=b; i--) #define REP(i, n) for(int i=0; i<n; i++) #define CLR(a, b) memset(a, b, sizeof(a)) #define debug puts("**debug**") #define LL long long #define PB push_back #define MP make_pair #define eps 1e-8 using namespace std; const int maxn = 60010; int T, n, m, v, a, b, k; vector<int> G[maxn]; int pre[maxn], lowlink[maxn], sccno[maxn], dfs_clock, scc_cnt; stack<int> s; void dfs(int u) { pre[u] = lowlink[u] = ++dfs_clock; s.push(u); for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if(!pre[v]) { dfs(v); lowlink[u] = min(lowlink[u], lowlink[v]); } else if(!sccno[v]) { lowlink[u] = min(lowlink[u], pre[v]); } } if(lowlink[u] == pre[u]) { scc_cnt++; for(;;) { int x = s.top(); s.pop(); sccno[x] = scc_cnt; if(x == u) break; } } } bool solve(int n) { dfs_clock = scc_cnt = 0; CLR(sccno, 0); CLR(pre, 0); REP(i, n*6) if(!pre[i]) dfs(i); REP(i, n) { if(sccno[i*6] == sccno[i*6+1]) return false; if(sccno[i*6+2] == sccno[i*6+3]) return false; if(sccno[i*6+4] == sccno[i*6+5]) return false; } return true; }; //石头 inline int R(int a) { return a*6; } inline int rR(int a) { return R(a) + 1; } //剪刀 inline int S(int a) { return a*6 + 2; } inline int rS(int a) { return S(a) + 1; } //布 inline int P(int a) { return a*6 + 4; } inline int rP(int a) { return P(a) + 1; } inline void add(int a, int b) { G[a].PB(b); } int main() { scanf("%d", &T); FF(kase, 1, T+1) { scanf("%d%d", &n, &m); REP(i, n*6) G[i].clear(); REP(i, n) { add(R(i), rS(i)); add(R(i), rP(i)); add(S(i), rR(i)); add(S(i), rP(i)); add(P(i), rS(i)); add(P(i), rR(i)); } REP(i, n) { scanf("%d", &v); if(v == 1) { add(rR(i), P(i)); add(rP(i), R(i)); } else if(v == 2) { add(rS(i), R(i)); add(rR(i), S(i)); } else { add(rP(i), S(i)); add(rS(i), P(i)); } } REP(i, m) { scanf("%d%d%d", &a, &b, &k); a--; b--; if(k) { add(R(a), rR(b)); add(R(b), rR(a)); add(S(a), rS(b)); add(S(b), rS(a)); add(P(a), rP(b)); add(P(b), rP(a)); } else { add(R(a), R(b)); add(R(b), R(a)); add(S(a), S(b)); add(S(b), S(a)); add(P(a), P(b)); add(P(b), P(a)); } } printf("Case #%d: %s\n", kase, solve(n) ? "yes" : "no"); } return 0; }