首先不难想到要先求割顶,求割顶的方法白书上有讲解
由于是一个矿崩塌,所以假如一个连通块连接了两个以上割顶,那么这个连通块内显然是不用设出口的
连接块只连接了一个割顶,那么出口可以设在这个连通块内任意位置
由此我们可以把两个问题解决了
注意特判一种情况,当不存在割顶的时候,至少要设两个出口
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 type node=record 2 po,next:longint; 3 end; 4 5 var w:array[0..500010] of node; 6 dfn,low,mark,cs,s,p:array[0..510] of longint; 7 v,cut:array[0..510] of boolean; 8 task,tot,t,i,x,y,len,n,m:longint; 9 ans:int64; 10 11 function min(a,b:longint):longint; 12 begin 13 if a>b then exit(b) else exit(a); 14 end; 15 16 procedure add(x,y:longint); 17 begin 18 inc(len); 19 w[len].po:=y; 20 w[len].next:=p[x]; 21 p[x]:=len; 22 end; 23 24 procedure dfs(x,fa:longint); 25 var i,y,ch:longint; 26 begin 27 inc(t); 28 dfn[x]:=t; 29 low[x]:=t; 30 i:=p[x]; 31 ch:=0; 32 while i<>-1 do 33 begin 34 y:=w[i].po; 35 if dfn[y]=0 then 36 begin 37 dfs(y,x); 38 inc(ch); 39 low[x]:=min(low[x],low[y]); 40 if low[y]>=dfn[x] then cut[x]:=true; //只要有子树不能连回当前点的祖先 41 end 42 else if (dfn[y]<dfn[x]) and (fa<>y) then //注意fa<>y 43 low[x]:=min(low[x],dfn[y]); 44 i:=w[i].next; 45 end; 46 if (fa<0) and (ch=1) then cut[x]:=false; //注意单链的首位不是割顶 47 end; 48 49 procedure color(x:longint); 50 var i,y:longint; 51 begin 52 i:=p[x]; 53 v[x]:=true; 54 inc(s[t]); 55 while i<>-1 do 56 begin 57 y:=w[i].po; 58 if not v[y] then 59 begin 60 if not cut[y] then color(y) 61 else if mark[y]<>t then 62 begin 63 mark[y]:=t; 64 inc(cs[t]); 65 end; 66 end; 67 i:=w[i].next; 68 end; 69 end; 70 71 begin 72 readln(m); 73 while m<>0 do 74 begin 75 inc(task); 76 len:=-1; 77 fillchar(p,sizeof(p),255); 78 n:=0; 79 for i:=1 to m do 80 begin 81 readln(x,y); 82 add(x,y); 83 add(y,x); 84 if x>n then n:=x; 85 if y>n then n:=y; 86 end; 87 fillchar(dfn,sizeof(dfn),0); 88 fillchar(cut,sizeof(cut),false); 89 for i:=1 to n do 90 if dfn[i]=0 then 91 begin 92 t:=0; 93 dfs(i,-1); 94 end; 95 ans:=1; 96 t:=0; 97 tot:=0; 98 fillchar(v,sizeof(v),false); 99 fillchar(mark,sizeof(mark),0); 100 fillchar(cs,sizeof(cs),0); 101 for i:=1 to n do 102 if not v[i] and not cut[i] then 103 begin 104 inc(t); 105 s[t]:=0; 106 color(i); 107 if cs[t]=1 then 108 begin 109 inc(tot); 110 ans:=ans*int64(s[t]); 111 end; 112 end; 113 if t=1 then //特判 114 begin 115 tot:=2; 116 ans:=n*(n-1) div 2; 117 end; 118 writeln('Case ',task,': ',tot,' ',ans); 119 readln(m); 120 end; 121 end.