3678

 
  
1 /*
2 属于2SAT验证的题目。判断是否存在2SAT解
3 首先用scc算法缩图,判断只要没有对应的两点在一个强连通分量里面就算右解
4 构图的方法:
5 a & b = 1, 则a和b都必须为1,那么如果a选择了0,也必须转到1,所以a0->a1,对于b也是b0-b1
6 a和b只要有选择0,都必须重定向到1
7
8 a & b = 0,则a和b只要有1个是0就行了,所以如果b选择了1,则a必须选0,a选择1的时候,b必须选0
9 b1->a0,a1->b0
10
11 a | b = 1,则a和b中只要有1个1就行了,所以如果a选择了0,则b必须选择1,如果b选择了0,a必须选择1
12 a0->b1,b0->a1
13
14 ....其余依次类推
15
16 */
17 // include file
18 #include < cstdio >
19 #include < cstdlib >
20 #include < cstring >
21 #include < cmath >
22 #include < cctype >
23 #include < ctime >
24
25 #include < iostream >
26 #include < sstream >
27 #include < fstream >
28 #include < iomanip >
29 #include < bitset >
30 #include < strstream >
31
32 #include < algorithm >
33 #include < string >
34 #include < vector >
35 #include < queue >
36 #include < set >
37 #include < list >
38 #include < functional >
39
40 using namespace std;
41
42 // typedef
43 typedef long long LL;
44 typedef unsigned long long ULL;
45
46 //
47 #define read freopen("in.txt","r",stdin)
48 #define write freopen("out.txt","w",stdout)
49 #define FORi(a,b) for(int i=(a);i<(b);i++)
50 #define FORj(a,b) for(int j=(a);j<(b);j++)
51
52 #define FF(i,a) for(int i=0;i<(a);i+++)
53 #define FFD(i,a) for(int i=(a)-1;i>=0;i--)
54 #define Z(a) (a<<1)
55 #define Y(a) (a>>1)
56
57 const double eps = 1e - 11 ;
58 const double Pi = acos( - 1.0 );
59
60 template < class T > inline T sqr(T a){ return a * a;}
61 template < class T > inline T TMAX(T x,T y)
62 {
63 if (x > y) return x;
64 return y;
65 }
66 template < class T > inline T MMAX(T x,T y,T z)
67 {
68 return TMAX(TMAX(x,y),z);
69 }
70
71 // code begin
72 #define MAXN 2010
73
74 vector < int > G[MAXN];
75
76 int scc;
77 int cnt;
78 int used[MAXN];
79 int stk1[MAXN],top1;
80 int stk2[MAXN],top2;
81 int isin[MAXN];
82 int dfn[MAXN];
83 int id[MAXN];
84 int N,M;
85
86 void gabow_scc( int i)
87 {
88 used[i] = true ;
89 stk1[top1 ++ ] = i;
90 stk2[top2 ++ ] = i;
91 dfn[i] = cnt ++ ;
92 isin[i] = true ;
93
94 FORj( 0 ,G[i].size() )
95 {
96 if ( ! used[ G[i][j] ])
97 {
98 gabow_scc(G[i][j]);
99 }
100 else if (isin[G[i][j]])
101 {
102 while (dfn[stk2[top2 - 1 ]] > dfn[G[i][j]])
103 top2 -- ;
104 }
105 }
106
107 if (i == stk2[top2 - 1 ])
108 {
109 top2 -- ;
110 int w;
111 do
112 {
113 w = stk1[ -- top1];
114 isin[w] = false ;
115 id[w] = scc;
116 } while (w != i);
117
118 scc ++ ;
119 }
120 }
121
122 int main()
123 {
124 read;
125 write;
126 while (scanf( " %d %d " , & N, & M) !=- 1 )
127 {
128 FORi( 0 , 2 * N)
129 {
130 G[i].clear();
131 }
132
133 // 建图
134 int a,b,c;
135 char op[ 5 ];
136 while (M -- )
137 {
138 scanf( " %d %d %d %s " , & a, & b, & c,op);
139 // 2*a 2*b
140 // 2*a+1 2*b+1
141 switch (op[ 0 ])
142 {
143 case ' A ' :
144 if (c)
145 {
146 G[ 2 * a].push_back( 2 * a + 1 );
147 G[ 2 * b].push_back( 2 * b + 1 );
148 }
149 else
150 {
151 G[ 2 * a + 1 ].push_back( 2 * b);
152 G[ 2 * b + 1 ].push_back( 2 * a);
153 }
154 break ;
155 case ' O ' :
156 if (c)
157 {
158 G[ 2 * a].push_back( 2 * b + 1 );
159 G[ 2 * b].push_back( 2 * a + 1 );
160 }
161 else
162 {
163 G[ 2 * a + 1 ].push_back( 2 * a);
164 G[ 2 * b + 1 ].push_back( 2 * b);
165 }
166 break ;
167 case ' X ' :
168 if (c)
169 {
170 G[ 2 * a].push_back( 2 * b + 1 );
171 G[ 2 * b + 1 ].push_back( 2 * a);
172 G[ 2 * b].push_back( 2 * a + 1 );
173 G[ 2 * a + 1 ].push_back( 2 * b);
174 }
175 else
176 {
177 G[ 2 * a].push_back( 2 * b);
178 G[ 2 * b].push_back( 2 * a);
179 G[ 2 * a + 1 ].push_back( 2 * b + 1 );
180 G[ 2 * b + 1 ].push_back( 2 * a + 1 );
181 }
182 break ;
183 }
184 }
185
186 // 运行gabow_scc
187 memset(used, 0 , sizeof (used));
188 memset(id, 0 , sizeof (used));
189 cnt = 1 ;
190 scc = 1 ;
191 top1 = top2 = 0 ;
192 FORi( 0 , 2 * N)
193 {
194 if ( ! used[i])
195 {
196 gabow_scc(i);
197 }
198 }
199
200 // 验证是否有2sat解
201 bool f = true ;
202 FORi( 0 ,N)
203 {
204 if ( id[i * 2 ] == id[i * 2 + 1 ] )
205 {
206 f = false ;
207 break ;
208 }
209 }
210 if (f) printf( " YES\n " );
211 else printf( " NO\n " );
212 }
213 return 0 ;
214 }

转载于:https://www.cnblogs.com/ac2012/archive/2011/02/28/1967349.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值