2723

1 /*
2 门是按顺序打开的,这点非常重要。
3
4 2SAT,建图,判断有有解
5 关于限制条件,对于key pair.有关系 a and b = 0,最多只能用1个,a1b0,a0b1,a0b0
6 对于门上的key pair,有关系 a or b = 1,只要有一个是1就行,a1b1 a1b0 a0b1
7 关系转化为边,可参考3678
8
9 可用二分加速
10 */
11
12 // include file
13 #include <cstdio>
14 #include <cstdlib>
15 #include <cstring>
16 #include <cmath>
17 #include <cctype>
18 #include <ctime>
19
20 #include <iostream>
21 #include <sstream>
22 #include <fstream>
23 #include <iomanip>
24 #include <bitset>
25 #include <strstream>
26
27 #include <algorithm>
28 #include <string>
29 #include <vector>
30 #include <queue>
31 #include <set>
32 #include <list>
33 #include <functional>
34
35 using namespace std;
36
37 // typedef
38 typedef long long LL;
39 typedef unsigned long long ULL;
40
41 //
42 #define read freopen("in.txt","r",stdin)
43 #define write freopen("out.txt","w",stdout)
44 #define FORi(a,b) for(int i=(a);i<(b);i++)
45 #define FORj(a,b) for(int j=(a);j<(b);j++)
46
47 #define FF(i,a) for(int i=0;i<(a);i+++)
48 #define FFD(i,a) for(int i=(a)-1;i>=0;i--)
49 #define Z(a) (a<<1)
50 #define Y(a) (a>>1)
51
52 const double eps = 1e-11;
53 const double Pi = acos(-1.0);
54
55 template<class T> inline T sqr(T a){return a*a;}
56 template<class T> inline T TMAX(T x,T y)
57 {
58 if(x>y) return x;
59 return y;
60 }
61 template<class T> inline T TMIN(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
72 // code begin
73 #define MAXN 5010
74
75 struct node
76 {
77 int a,b;
78 };
79
80 node key[MAXN];
81 node door[MAXN];
82
83 vector<int> G[MAXN];
84
85 int scc;
86 int cnt;
87 int used[MAXN];
88 int stk1[MAXN],top1;
89 int stk2[MAXN],top2;
90 int isin[MAXN];
91 int dfn[MAXN];
92 int low[MAXN];
93 int id[MAXN];
94 int N,M;
95
96 void gabow_scc(int i)
97 {
98 used[i] = true;
99 stk1[top1++] = i;
100 stk2[top2++] = i;
101 dfn[i] = cnt++;
102 isin[i] = true;
103
104 FORj( 0,G[i].size() )
105 {
106 if(!used[ G[i][j] ])
107 {
108 gabow_scc(G[i][j]);
109 }
110 else if(isin[G[i][j]])
111 {
112 while(dfn[stk2[top2-1]]>dfn[G[i][j]])
113 top2--;
114 }
115 }
116
117 if(i==stk2[top2-1])
118 {
119 top2--;
120 int w;
121 do
122 {
123 w = stk1[--top1];
124 isin[w] = false;
125 id[w] = scc;
126 }while(w!=i);
127
128 scc++;
129 }
130 }
131
132 void tarjan_scc(int i)
133 {
134 used[i] = true;
135 stk1[top1++] = i;
136 dfn[i] = cnt;
137 low[i] = cnt;
138 cnt++;
139 isin[i] = true;
140
141 FORj(0,G[i].size())
142 {
143 if(!used[ G[i][j] ])
144 {
145 tarjan_scc(G[i][j]);
146 low[i] = TMIN(low[i],low[G[i][j]]);
147 }
148 else if(isin[G[i][j]])
149 {
150 low[i] = TMIN(low[i],dfn[G[i][j]]);
151 }
152 }
153
154 if(dfn[i]==low[i])
155 {
156 int w;
157 do
158 {
159 w=stk1[--top1];
160 isin[w] = false;
161 id[w] = scc;
162 }while(w!=i);
163 scc++;
164 }
165 }
166
167 void build_G(int sz)
168 {
169 FORi(0,N*4)
170 {
171 G[i].clear();
172 }
173 int a,b;
174 FORi(0,N)
175 {
176 // a and b = 0
177 a=key[i].a;
178 b=key[i].b;
179 G[2*a+1].push_back(2*b);
180 G[2*b+1].push_back(2*a);
181 }
182 FORi(0,sz)
183 {
184 // a or b = 1
185 a = door[i].a;
186 b = door[i].b;
187 G[2*a].push_back(2*b+1);
188 //G[2*b+1].push_back(2*a);
189 G[2*b].push_back(2*a+1);
190 //G[2*a+1].push_back(2*b);
191 }
192 }
193
194 bool SAT(int mid)
195 {
196 if(mid==0) return true;
197 memset(used,0,sizeof(used));
198 memset(id,0,sizeof(id));
199 top1 = top2 = 0;
200 cnt = 1;
201 scc = 1;
202 memset(isin,0,sizeof(isin));
203 memset(dfn,0,sizeof(dfn));
204 memset(low,0,sizeof(low));
205 FORi(0,N*4)
206 {
207 if(!used[i])
208 {
209 //gabow_scc(i);
210 tarjan_scc(i);
211 }
212 }
213
214 FORi(0,N*2)
215 {
216 if(id[2*i]==id[2*i+1])
217 return false;
218 }
219 return true;
220 }
221
222 int main()
223 {
224 read;
225 write;
226 while(scanf("%d %d",&N,&M)!=-1)
227 {
228 if(N+M==0) break;
229
230 int a,b;
231 FORi(0,N)
232 {
233 scanf("%d %d",&a,&b);
234 key[i].a = a;
235 key[i].b = b;
236 }
237
238 FORi(0,M)
239 {
240 scanf("%d %d",&a,&b);
241 door[i].a = a;
242 door[i].b = b;
243 }
244
245 //0..M
246 int L=0,R=M+1,ans=0;
247
248 while(L<R)
249 {
250 int mid = Y(L+R);
251 // 0到mid-1建模
252
253 build_G(mid);
254 if(SAT(mid))
255 {
256 if(mid>ans) ans=mid;
257 L=mid+1;
258 }
259 else R=mid;
260 }
261
262 printf("%d\n",ans);
263 }
264 return 0;
265 }
posted @ 2011-02-28 21:54  AC2012  阅读(442)  评论(0编辑  收藏  举报