Poj--3678(2-SAT,强连通分量)

2014-10-16 21:08:49

思路:这道算经典的2-SAT了,各种操作。(设A0,A1分为别指派A点为真 / 假)

  比较奇妙的是(1)令A点为真,则建边:A0 -> A1

        (2)令A点为假,则建边:A1 -> A0

  这样的话如果:A的指派为真,一旦到A0这个点那么必须到A1,这样就让A0,A1在同个SCC中,形成矛盾。

  1 #include <cstdio>
  2 #include <iostream>
  3 #include <cstring>
  4 #include <stack>
  5 using namespace std;
  6 const int maxn = 1010;
  7 
  8 int first[maxn << 1],next[maxn * maxn],ver[maxn * maxn],ecnt;
  9 int low[maxn << 1],dfn[maxn << 1],sc[maxn << 1],scnt,tot;
 10 int N,M;
 11 stack<int> s;
 12 
 13 void Add_edge(int u,int v){
 14     next[++ecnt] = first[u];
 15     ver[ecnt] = v;
 16     first[u] = ecnt;
 17 }
 18 
 19 void Init(){
 20     memset(first,-1,sizeof(first));
 21     ecnt = tot = scnt = 0;
 22 }
 23 
 24 void Dfs1(int p){
 25     dfn[p] = low[p] = ++tot;
 26     s.push(p);
 27     for(int i = first[p]; i != -1; i = next[i]){
 28         int v =ver[i];
 29         if(!dfn[v]){
 30             Dfs1(v);
 31             low[p] = min(low[p],low[v]);
 32         }
 33         else if(!sc[v]){
 34             low[p] = min(low[p],dfn[v]);
 35         }
 36     }
 37     if(low[p] == dfn[p]){
 38         ++scnt;
 39         while(1){
 40             int x = s.top();
 41             s.pop();
 42             sc[x] = scnt;
 43             if(x == p) break;
 44         }
 45     }
 46 }
 47 
 48 void Tarjan(){
 49     memset(low,0,sizeof(low));
 50     memset(dfn,0,sizeof(dfn));
 51     memset(sc,0,sizeof(sc));
 52     while(!s.empty()) s.pop();
 53     int top = 2 * N;
 54     for(int i = 0; i < top; ++i)
 55         if(!dfn[i]) Dfs1(i);
 56 }
 57 
 58 int main(){
 59     int a,b,c;
 60     char op[10];
 61     while(scanf("%d%d",&N,&M) != EOF){
 62         Init();
 63         for(int i = 1; i <= M; ++i){
 64             scanf("%d%d%d%s",&a,&b,&c,op);
 65             if(op[0] == 'A'){
 66                 if(c == 1){
 67                     Add_edge(a * 2,a * 2 + 1); // true a
 68                     Add_edge(b * 2,b * 2 + 1); // true b
 69                 }
 70                 else{
 71                     Add_edge(a * 2 + 1,b * 2);
 72                     Add_edge(b * 2 + 1,a * 2);
 73                 }
 74             }
 75             else if(op[0] == 'O'){
 76                 if(c == 1){
 77                     Add_edge(a * 2,b * 2 + 1);
 78                     Add_edge(b * 2,a * 2 + 1);
 79                 }
 80                 else{
 81                     Add_edge(a * 2 + 1,a * 2); // not a
 82                     Add_edge(b * 2 + 1,b * 2); // not b
 83                 }
 84             }
 85             else{
 86                 if(c == 1){
 87                     Add_edge(a * 2 + 1,b * 2);
 88                     Add_edge(a * 2,b * 2 + 1);
 89                     Add_edge(b * 2 + 1,a * 2);
 90                     Add_edge(b * 2,a * 2 + 1);
 91                 }
 92                 else{
 93                     Add_edge(a * 2,b * 2);
 94                     Add_edge(b * 2,a * 2);
 95                     Add_edge(a * 2 + 1,b * 2 + 1);
 96                     Add_edge(b * 2 + 1,a * 2 + 1);
 97                 }
 98             }
 99         }
100         Tarjan();
101         int flag = 1;
102         for(int i = 0; i < N; ++i){
103             if(sc[i * 2] == sc[i * 2 + 1]){
104                 flag = 0;
105                 break;
106             }
107         }
108         if(flag) printf("YES\n");
109         else printf("NO\n");
110     }
111     return 0;
112 }

 

转载于:https://www.cnblogs.com/naturepengchen/articles/4029729.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值