hdu 4115(2-SAT) 2011 成都现场赛E题

题意:两个人玩剪刀石头布,你知道对手出拳的序列(就是每一步出哪个)给你两种限制,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  都能出的为真

代码如下:

  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 }
View Code
奔跑吧!少年!趁着你还年轻
原文地址:https://www.cnblogs.com/shu-xiaohao/p/3618269.html