2942

1 /*
2 题目大意是:一些骑士,他们都有自己的仇人,所以安排座位的时候,必须邻座没有仇人。
3 但是某些人可能无法安排座位,问无法安排座位的人有多少个
4
5 解法:把所有的仇人关系建立图,求补图,在补图中,所有连接边的两个顶点可以做邻居
6 这个图可能存在割点,所以我们要找出连通分量,如果连通分量存在奇圈,那么可以满足,如果不存在
7 去除所有该连通分量的人
8
9 最后输出去除的人数
10
11 这道题让我知道了我写的点连通分量是有问题的,在碰到割点的时候,从栈中输出分量,碰到割点连接的儿子的时候停止
12 可是我写的是当下一个点是割点的时候停止,就这一点小小的不同,就一直WA.现在我还不知道为什么会错,因为割点和它的儿子在栈中
13 是不连续的吗?
14 */
15
16
17
18 // include file
19 #include <cstdio>
20 #include <cstdlib>
21 #include <cstring>
22 #include <cmath>
23 #include <cctype>
24 #include <ctime>
25
26 #include <iostream>
27 #include <sstream>
28 #include <fstream>
29 #include <iomanip>
30 #include <bitset>
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 typedef __int64 Bint;
46
47 //
48 #define read freopen("in.txt","r",stdin)
49 #define write freopen("out.txt","w",stdout)
50 #define FORi(a,b,c) for(int i=(a);i<(b);i+=c)
51 #define FORj(a,b,c) for(int j=(a);j<(b);j+=c)
52 #define FORk(a,b,c) for(int k=(a);k<(b);k+=c)
53 #define FORp(a,b,c) for(int p=(a);p<(b);p+=c)
54 #define FORii(a,b,c) for(int ii=(a);ii<(b);ii+=c)
55 #define FORjj(a,b,c) for(int jj=(a);jj<(b);jj+=c)
56 #define FORkk(a,b,c) for(int kk=(a);kk<(b);kk+=c)
57
58 #define FF(i,a) for(int i=0;i<(a);i++)
59 #define FFD(i,a) for(int i=(a)-1;i>=0;i--)
60
61 #define Z(a) (a<<1)
62 #define Y(a) (a>>1)
63
64 const double eps = 1e-6;
65 const double INFf = 1e10;
66 const int INFi = 1000000000;
67 const double Pi = acos(-1.0);
68
69 template<class T> inline T sqr(T a){return a*a;}
70 template<class T> inline T TMAX(T x,T y)
71 {
72 if(x>y) return x;
73 return y;
74 }
75 template<class T> inline T TMIN(T x,T y)
76 {
77 if(x<y) return x;
78 return y;
79 }
80 template<class T> inline void SWAP(T &x,T &y)
81 {
82 T t = x;
83 x = y;
84 y = t;
85 }
86 template<class T> inline T MMAX(T x,T y,T z)
87 {
88 return TMAX(TMAX(x,y),z);
89 }
90
91
92 // code begin
93 #define MAXN 1010
94 #define MAXM 1000010
95 bool mp[MAXN][MAXN];
96 struct node1
97 {
98 int e;
99 int next;
100 };
101 struct node2
102 {
103 int next;
104 };
105 node1 mem[MAXM];
106 node2 G[MAXN];
107 int N,M;
108
109 int dfn[MAXN]; ///
110 int low[MAXN]; //
111 bool used[MAXN]; //
112 int cnt;
113
114 int stk[MAXN],top; // 辅助栈
115 int block[MAXN]; // 存贮快
116 int bsize; //每个块的大小
117
118 bool expll[MAXN]; //判断某个点是否被剔除
119 bool bused[MAXN]; //辅助判断二分图用
120 bool bvist[MAXN];
121 int color[MAXN]; //染色用
122 bool ok;
123
124 void Add_edge(int dx,int a,int b)
125 {
126 mem[dx].e = b;
127 mem[dx].next = G[a].next;
128 G[a].next = dx;
129 }
130
131 void Isbipartial( int st,int co)
132 {
133 if(!ok) return;
134 color[st] = co;
135 bvist[st] = true;
136 int dx = G[st].next;
137 while(dx!=-1)
138 {
139 int v = mem[dx].e;
140 if( bused[v] )
141 {
142 if(!bvist[v])
143 {
144 Isbipartial(v,5-co);
145 if(!ok) return;
146 }
147 else
148 {
149 if(color[v]==color[st])
150 {
151 ok = false;
152 return;
153 }
154 }
155 }
156 dx = mem[dx].next;
157 }
158 }
159
160 void BCC_tarjan(int i,int fa)
161 {
162 dfn[i] = cnt;
163 low[i] = cnt;
164 used[i] = true;
165 cnt ++;
166 stk[top++] = i;
167 int dx = G[i].next;
168 while(dx!=-1)
169 {
170 int v = mem[dx].e;
171 if(!used[v])
172 {
173 BCC_tarjan(v,i);
174 low[i] = TMIN(low[i],low[v]);
175
176 if(low[v]>=dfn[i])
177 {// 割点
178
179 memset(bused,0,sizeof(bused));
180 memset(color,0,sizeof(color));
181 memset(bvist,0,sizeof(bvist));
182 int tp;
183 bsize = 0;
184
185 do
186 {
187 tp = stk[--top];
188 block[bsize++] = tp;
189 bused[tp] = true;
190 }while(tp != v); //退出到v就可以了,u还可以在别的其他的块中
191
192
193 /*
194 while(stk[top-1]!=i)
195 {
196 tp = stk[--top];
197 block[bsize++] = tp;
198 bused[tp] = true;
199 }
200 */
201
202 block[bsize++] = i;
203 bused[i] = true;
204
205 ok = true;
206 Isbipartial(i,2);
207 if( !ok ) //如果是二分图,那么所有的点都要被剔除了,因为它们形成不了奇圈
208 {
209 FORj(0,bsize,1)
210 expll[block[j]] = true;
211 }
212
213
214 }
215 }
216 else if(v!=fa)
217 {
218 low[i] = TMIN(low[i],dfn[v]);
219 }
220
221 dx = mem[dx].next;
222 }
223
224 }
225
226 int main()
227 {
228 read;
229 write;
230 int dx,a,b;
231 while(scanf("%d %d",&N,&M)!=-1)
232 {
233 if(N+M==0)
234 {
235 break;
236 }
237 dx = 0;
238 memset(mp,0,sizeof(mp));
239 FORi(0,M,1)
240 {
241 scanf("%d %d",&a,&b);
242 mp[a][b] = 1;
243 mp[b][a] = 1;
244 }
245
246 FORi(1,N+1,1)
247 {
248 G[i].next = -1;
249 }
250 // 建立补图
251 FORi(1,N+1,1)
252 {
253 FORj(1,N+1,1)
254 {
255 if(!mp[i][j]&&i!=j)
256 {
257 Add_edge(dx++,i,j);
258 }
259 }
260 }
261
262 //CheckG();
263
264 // 求点连通分量
265 memset(dfn,0,sizeof(dfn));
266 memset(low,0,sizeof(low));
267 memset(used,0,sizeof(used));
268 cnt = 1;
269 top = 0;
270 memset(expll,0,sizeof(expll));
271 FORi(1,N+1,1)
272 {
273 if(!used[i])
274 {
275 BCC_tarjan(i,-1);
276 }
277 }
278
279 //
280 int ans = 0;
281 FORi(1,N+1,1)
282 {
283 if(expll[i])
284 ans++;
285 }
286 printf("%d\n",N-ans);
287 }
288 return 0;
289 }

posted @ 2011-03-14 10:10  AC2012  阅读(451)  评论(0编辑  收藏  举报