题意:两个人玩剪刀石头布,你知道对手出拳的序列(就是每一步出哪个)给你两种限制,i与j相同和不相同。你赢的条件是你不能输给对方一次,问你能不能赢。
思路:典型的2-SAT题目,对于每次猜拳,排除你会输的那一次然后就只剩两个选择了,接下来就是分类讨论。
我们定义第一个能出的为真,另一个为假
首先分成 i次 与j次不能出的相同,那么
a b 1 表示 a^b = 1
a b 0 表示 a^b = 0
然后是不同的,那么
对于a b 1情况
a b 出那个已经知道了
a b 0情况
!a->b ^ !b->a 都能出的为假
a->!b ^ b->!a 都能出的为真
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /************************************************** 2 * Author : xiaohao Z 3 * Blog : http://www.cnblogs.com/shu-xiaohao/ 4 * Last modified : 2014-03-22 16:59 5 * Filename : hdu_chengdu2.cpp 6 * Description : 7 * ************************************************/ 8 9 #include <iostream> 10 #include <cstdio> 11 #include <cstring> 12 #include <cstdlib> 13 #include <cmath> 14 #include <algorithm> 15 #include <queue> 16 #include <stack> 17 #include <vector> 18 #include <set> 19 #include <map> 20 #define MP(a, b) make_pair(a, b) 21 #define PB(a) push_back(a) 22 23 using namespace std; 24 typedef long long ll; 25 typedef pair<int, int> pii; 26 typedef pair<unsigned int,unsigned int> puu; 27 typedef pair<int, double> pid; 28 typedef pair<ll, int> pli; 29 typedef pair<int, ll> pil; 30 31 const int INF = 0x3f3f3f3f; 32 const double eps = 1E-6; 33 const int LEN = 100000+10; 34 int n, m, chu[LEN][4], vis[LEN], sccn[LEN]; 35 vector<int> Map[LEN], rMap[LEN], vs; 36 37 void dfs(int v){ 38 vis[v] = 1; 39 for(int i=0; i<Map[v].size(); i++) if(!vis[Map[v][i]]) dfs(Map[v][i]); 40 vs.PB(v); 41 } 42 43 void rdfs(int v, int k){ 44 vis[v] = 1; 45 sccn[v] = k; 46 for(int i=0; i<rMap[v].size(); i++) if(!vis[rMap[v][i]]) rdfs(rMap[v][i], k); 47 } 48 49 int scc(){ 50 memset(vis, 0, sizeof vis); 51 vs.clear(); 52 for(int v=0; v<2*n; v++) if(!vis[v]) dfs(v); 53 memset(vis, 0, sizeof vis); 54 int k = 0; 55 for(int i=vs.size()-1; i>=0; i--) if(!vis[vs[i]]) rdfs(vs[i], k++); 56 return k; 57 } 58 59 bool twosat(){ 60 scc(); 61 // for(int i=0; i<2*n; i++)cout << sccn[i] << ' '; 62 // cout << endl; 63 for(int i=0; i<2*n; i+=2){ 64 if(sccn[i] == sccn[i^1]){ 65 //cout << i << endl; 66 return false; 67 } 68 } 69 return true; 70 } 71 72 void add(int a, int b){ 73 Map[a].PB(b); 74 rMap[b].PB(a); 75 } 76 77 void addNot(int a, int b){ 78 a*=2; b*=2; 79 add(a, b^1); 80 add(b^1, a); 81 add(b, a^1); 82 add(a^1, b); 83 } 84 85 void addYes(int a, int b){ 86 a*=2; b*=2; 87 add(a, b); 88 add(b, a); 89 add(a^1, b^1); 90 add(b^1, a^1); 91 } 92 93 void addSame(int a){ 94 add(a^1, a); 95 } 96 97 void addNotSame(int a, int b){ 98 add(a, b^1); 99 add(b, a^1); 100 } 101 102 int main() 103 { 104 // freopen("in.txt", "r", stdin); 105 106 int T, a, b, c; 107 scanf("%d", &T); 108 for(int kase=1; kase<=T; kase++){ 109 for(int i=0; i<LEN; i++) Map[i].clear(); 110 for(int i=0; i<LEN; i++) rMap[i].clear(); 111 memset(chu, 0, sizeof chu); 112 scanf("%d%d", &n, &m); 113 for(int i=0; i<n; i++){ 114 int tmp; 115 scanf("%d", &tmp); 116 chu[i][0] = tmp; 117 chu[i][(tmp)%3+1] = 1; 118 } 119 for(int i=0; i<m; i++){ 120 scanf("%d%d%d", &a, &b, &c); 121 a--; b--; 122 if(chu[a][0] == chu[b][0]){ 123 if(c == 1) addNot(a, b); 124 else addYes(a, b); 125 }else{ 126 int fa = -1, fb = -1; 127 for(int j=1; j<4; j++){ 128 if(!chu[a][j]) fa++; 129 if(!chu[b][j]) fb++; 130 if(chu[a][j] == chu[b][j] && chu[b][j] == 0) break; 131 } 132 if(c == 0){ 133 addSame((2*a)^fa); 134 addSame((2*b)^fb); 135 }else{ 136 addNotSame((2*a)^fa, (2*b)^fb); 137 } 138 } 139 } 140 printf("Case #%d: ", kase); 141 if(twosat())printf("yes "); 142 else printf("no "); 143 } 144 return 0; 145 }