【2-SAT】POJ3678-Katu Puzzle

【题目大意】

给出有向图G(V, E),每条边(a,b)有一个值c(c=0或1)和运算符op,问能否找到这一张有向图,满足所有的a op b=c?

【思路】

显然是2-SAT。不过要注意一定,如a and b=1,若a=0是必定无解的。像这种情况,要连边a+n->a;同理所有类似于a or b=0,也要两边a->a+n。即无解清新要保证自己连到自己的相反情形。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<vector>
 6 #include<stack>
 7 using namespace std;
 8 const int MAXN=1000+50;
 9 vector<int> E[MAXN];
10 stack<int> s;
11 int low[MAXN],dfn[MAXN],cnt=0,bcnt=0;
12 int instack[MAXN],b[MAXN];
13 int n,m;
14 
15 void addedge(int u,int v)
16 {
17     E[u].push_back(v);
18 }
19 
20 void tarjan(int u)
21 {
22     dfn[u]=low[u]=++cnt;
23     instack[u]=1;
24     s.push(u);
25     for (int i=0;i<E[u].size();i++)
26     {
27         int to=E[u][i];
28         if (!instack[to]) tarjan(to),low[u]=min(low[u],low[to]);
29             else if (instack[to]==1) low[u]=min(low[u],dfn[to]);
30     }
31     
32     if (dfn[u]==low[u])
33     {
34         int x;
35         ++bcnt;
36         do
37         {
38             x=s.top();s.pop();
39             instack[x]=2;
40             b[x]=bcnt;
41         }while (x!=u);
42     }
43 }
44 
45 void init()
46 {
47     scanf("%d%d",&n,&m);
48     for (int i=0;i<m;i++)
49     {
50         int a,b,c;char op[5];
51         scanf("%d%d%d%s",&a,&b,&c,op);
52         a++,b++;
53         if (op[0]=='A')
54         {
55             if (c==0) addedge(a,b+n),addedge(b,a+n);
56             if (c==1) addedge(a,b),addedge(b,a),addedge(a+n,a),addedge(b+n,b);
57         }
58         if (op[0]=='O')
59         {
60             if (c==0) addedge(a+n,b+n),addedge(b+n,a+n),addedge(a,a+n),addedge(b,b+n);
61             if (c==1) addedge(a+n,b),addedge(b+n,a);
62         }
63         if (op[0]=='X')
64         {
65             if (c==0) addedge(a,b),addedge(b,a),addedge(a+n,b+n),addedge(b+n,a+n);
66             if (c==1) addedge(a+n,b),addedge(b+n,a),addedge(a,b+n),addedge(b,a+n); 
67         }
68     }
69 }
70 
71 void solve()
72 {
73     memset(instack,0,sizeof(instack));
74     for (int i=1;i<=2*n;i++) if (!instack[i]) tarjan(i); 
75     int flag=1;
76     for (int i=1;i<=n;i++)
77         if (b[i]==b[i+n])
78         {
79             flag=0;
80             break;
81         }
82     puts(flag?"YES":"NO");
83 }
84 
85 int main()
86 {
87     init();
88     solve();
89     return 0;
90 }

 

转载于:https://www.cnblogs.com/iiyiyi/p/5709900.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值