hdu 4115 2-SAT

  1 /*
  2 题解:2-SAT
  3 一开始每一个round都有两种状态可选,并且选了每种状态有后面的限制其中一种选后另一状态的状态也被固定,
  4 十分符合2-SAT的用法;
  5 */
  6 #include <cstdio>
  7 #include <cstring>
  8 #include <iostream>
  9 #include <vector>
 10 #include <queue>
 11 
 12 #define clr(a,b) (memset(a,b,sizeof(a)))
 13 #define cpy(a,b) (memcpy(a,b,sizeof(b)))
 14 
 15 using namespace std;
 16 
 17 const int NV = 20005; // 点数要注意,后面是有两个点集
 18 const int NE = 200005; // 边也要注意加边的数量不只是限制条件的数目,因为一个限制条件可能要加几条边
 19 const int W = 0;
 20 const int R = 1;
 21 const int B = 2;
 22 
 23 int opp[NV];
 24 int in[NV];
 25 bool ans[NV];
 26 int col[NV];
 27 int n, nn, m;
 28 inline int Min(int a, int b) {return a < b ? a : b;}
 29 struct SCC {
 30     int deep,scc, top, SZ, n;
 31     struct edge {int v, next;} E[NE];
 32     int pre[NV], dep[NV], low[NV], id[NV], st[NV];
 33     bool in[NV];
 34     inline void init(int _n) {
 35         n = _n;
 36         clr(pre, -1);
 37         clr(dep, -1);
 38         clr(in,false);
 39         deep = scc = SZ = top = 0;
 40     }
 41     void tarjan(int u) {
 42         int v, i;
 43         dep[u] = low[u] = ++ deep;
 44         st[top++] = u;
 45 
 46         in[u] = true;
 47         for (i = pre[u]; i != -1; i = E[i].next) {
 48             v = E[i].v;
 49             if (dep[v] == -1) {
 50                 tarjan(v);
 51                 low[u] = Min(low[u], low[v]);
 52             }
 53             else if (in[v]) {
 54                 low[u] = Min(low[u], dep[v]);
 55             }
 56         }
 57         if (low[u] == dep[u]) {
 58             do {
 59                 v = st[--top];
 60                 in[v] = false;
 61                 id[v] = scc;
 62             } while (u != v);
 63             scc ++;
 64         }
 65     }
 66     inline void insert(int u, int v) {
 67         E[SZ].v = v;
 68         E[SZ].next = pre[u];
 69         pre[u] = SZ ++;
 70     }
 71     inline void solve() {
 72         for (int i = 0; i < n; i++) {
 73             if (dep[i] == -1) {
 74                 tarjan(i);
 75             }
 76         }
 77     }
 78 } G;
 79 int main(void) {
 80     int i, j;
 81     int x, y;
 82     int t;
 83     int alice[20005];
 84     scanf("%d",&t);
 85     for(int cas=1; cas<=t; cas++)
 86     {
 87         int n,m;
 88         scanf("%d%d", &n, &m);
 89         nn = n * 2; // 正反两个点集
 90         for (i = 0; i < nn; i++)
 91             opp[i] = (i ^ 1);
 92 
 93         G.init(nn);
 94         for(int i=0; i<nn; i+=2)
 95         {
 96             int cc;
 97             scanf("%d",&cc);
 98             switch(cc)
 99             {
100             case 1: alice[i] = 1,alice[opp[i]] = 2; break;
101             case 2: alice[i] = 2,alice[opp[i]] = 3; break;
102             case 3: alice[i] = 3,alice[opp[i]] = 1; break;
103             }
104         }
105         for (i = 0; i < m; i++) {
106             int a, b, k;
107             scanf("%d%d%d", &a, &b, &k);
108             a--;
109             a*=2;
110             b--;
111             b*=2;
112             /*
113             此处加边要注意是从0开始,而且偶数为该点集,奇数为对立点集
114             G.insert(x, opp[y]);
115             G.insert(y, opp[x]);
116             */
117             if (k)
118             {
119                 if (alice[a] == alice[b]) // 相等说明a必然要退出opp[b]才能得到正确结果,反过来亦然
120                 {
121                     G.insert(a,opp[b]);
122                     G.insert(b,opp[a]);
123                 }
124                 if (alice[a] == alice[opp[b]])
125                 {
126                     G.insert(a,b);
127                     G.insert(opp[b],opp[a]);
128                 }
129                 if (alice[opp[a]] == alice[b])
130                 {
131                     G.insert(opp[a],opp[b]);
132                     G.insert(b,a);
133                 }
134                 if (alice[opp[a]] == alice[opp[b]])
135                 {
136                     G.insert(opp[a],b);
137                     G.insert(opp[b],a);
138                 }
139             }
140             else
141             {
142                 if (alice[a] != alice[b])
143                 {
144                     G.insert(a,opp[b]);
145                     G.insert(b,opp[a]);
146                 }
147                 if (alice[a] != alice[opp[b]])
148                 {
149                     G.insert(a,b);
150                     G.insert(opp[b],opp[a]);
151                 }
152                 if (alice[opp[a]] != alice[b])
153                 {
154                     G.insert(opp[a],opp[b]);
155                     G.insert(b,a);
156                 }
157                 if (alice[opp[a]] != alice[opp[b]])
158                 {
159                     G.insert(opp[a],b);
160                     G.insert(opp[b],a);
161                 }
162             }
163         }
164         G.solve();
165         for (i = 0; i < nn; i += 2) {
166             if (G.id[i] == G.id[opp[i]]) {
167                 break;
168             }
169         }
170         if (i < nn) { // 不存在
171             printf("Case #%d: no\n",cas);
172         }
173         else
174             printf("Case #%d: yes\n",cas);
175     }
176     return 0;
177 }

 

转载于:https://www.cnblogs.com/toufu/p/3719645.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值