码迷,mamicode.com
首页 > Web开发 > 详细

[bzoj1005] [JSOI2008]星球大战starwar

时间:2016-05-01 06:23:19      阅读:260      评论:0      收藏:0      [点我收藏+]

标签:

想了半天决定第一篇就发一道水题的题解吧……这道题以前就看了但是神奇的第一次没有写对,然后今天写代码+调试,额……二十分钟……

题目懒得贴了,直接戳这里

题目大意就是给你一个图(毫无疑问稀疏图),然后每一次抹去其中一个节点,然后求这时的连通块个数。

第一次看这题的时候在学tarjan,第一反应就是每次把点去掉跑tarjan,然后看了下数据范围就放弃了【其实也能过几个点对不对233】

然后就想到用并查集,把所有的操作全部用一个数组存下来,然后倒着合并。

首先将所有要消除的点全部抹去,用并查集求出当前连通块的个数,然后根据给出的顺序,每一次“激活”一个点,然后和它所连的激活的点合并,最后倒着输出就可以了。

关于合并统计连通块个数:

①将所有要消除的点抹去后,ans:=n-k,然后在当前图中开始合并,即如果发现有两个点有边相连且不在同一个连通块中,那么合并两个连通块且ans:=ans-1。最后统计出的就是将所有指定的星球全部毁灭后的连通块个数

②添加点时注意ans:=ans+1,因为当添加了一个点就相当于又添加了一个连通块.然后合并,统计方法和上面一样,如果不在一个连通块中则ans:=ans-1.此时统计出的是在当前所添加的星球未被毁灭之前的连通块个数

还有要注意的一点就是数据范围比较大,邻接矩阵不够存要用邻接表。另外为了时间更快用的并查集的路径压缩(不会直接度娘)

其他的就什么好说的了,我属于代码写的比较丑的类型也只写了八十多行,下面贴代码

 1 program j01;
 2 var x,y,n,m,i,j,k,t,ans:longint;
 3     f:array[0..500000]of longint;
 4     a,c:array[1..500000]of longint;
 5     b:array[0..500000]of boolean;
 6     q,next,head:array[0..500000]of longint;
 7 function gg(i:longint):longint;//并查集查找部分,这里为了时间快用了压缩路径
 8 var x:longint;
 9 begin
10   if f[i]=i then exit(i);
11   x:=gg(f[i]);
12   f[i]:=x;
13   exit(x);
14 end;
15 procedure merge(i,j:longint);
16 var x,y:longint;
17 begin
18   x:=gg(i);
19   y:=gg(j);
20   f[x]:=y;
21 end;
22 procedure add(a,b:longint);//邻接表
23 begin
24   inc(t);
25   q[t]:=b;
26   next[t]:=head[a];
27   head[a]:=t;
28 end;
29 begin
30   readln(n,m);
31   fillchar(head,sizeof(head),0);
32   t:=0;
33   for i:=1 to m do
34   begin
35     readln(x,y);
36     add(x,y);
37     add(y,x);
38   end;
39   readln(k);
40   fillchar(b,sizeof(b),true);
41   for i:=1 to k do
42   begin
43     readln(a[i]);
44     b[a[i]]:=false;
45   end;
46   ans:=n-k;
47   for i:=0 to n-1 do f[i]:=i;
48   for i:=0 to n-1 do
49   begin
50     j:=head[i];
51     if b[i] then
52       while j<>0 do
53       begin
54         if b[q[j]] then
55           if gg(i)<>gg(q[j]) then
56           begin
57             dec(ans);
58             merge(i,q[j]);
59           end;
60         j:=next[j];
61       end;
62   end;//统计最后连通块个数
63   for i:=k downto 1 do
64   begin
65     c[i]:=ans;//这里的ans记录的是i+1次毁灭星球之前连通块个数,即i次毁灭星球是后的连通块个数
66     b[a[i]]:=true;
67     ans:=ans+1;
68     j:=head[a[i]];
69     while j<>0 do
70     begin
71       if b[q[j]] then
72         if gg(a[i])<>gg(q[j]) then
73         begin
74           dec(ans);
75           merge(a[i],q[j]);
76         end;
77       j:=next[j];
78     end;
79   end;//统计每一次毁灭前连通块个数
80   writeln(ans);
81   for i:=1 to k do writeln(c[i]);
82 end.

 

[bzoj1005] [JSOI2008]星球大战starwar

标签:

原文地址:http://www.cnblogs.com/oldjang/p/5449838.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!