https://www.luogu.org/problemnew/show/P3225
用Tarjan跑出割点,然后DFS搜索所有的联通快
计算每一个联通快中的割点数目
分类讨论:
如果没有割点
至少需要建立两个出口
从任意非割点的地方选择两个点建立
如果这个分组只有一个割点
只需要在分组内设立一个出口
可以设立在任意一个非割点的地方
如果有两个及以上个割点,则无需建立,可以直接到达其他联通块

1 #include<iostream>
2 #include<cstring>
3 #include<cstdio>
4 #include<algorithm>
5 using namespace std;
6 inline int read(){
7 int sum=0,x=1;
8 char ch=getchar();
9 while(ch<'0'||ch>'9'){
10 if(ch=='-')
11 x=0;
12 ch=getchar();
13 }
14 while(ch>='0'&&ch<='9')
15 sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
16 return x?sum:-sum;
17 }
18 inline void write(int x){
19 if(x<0)
20 putchar('-'),x=-x;
21 if(x>9)
22 write(x/10);
23 putchar(x%10+'0');
24 }
25 typedef long long ll;
26 const int M=520;
27 ll ans1,ans2;
28 int n,m;
29 ll tot,cnt,root,child,liantong,vnum,cutnum;
30 struct node{
31 int v,nextt;
32 }e[M*M];
33 int vis[M],dfn[M],low[M],head[M],cut[M];
34 void tarjan(int u,int f){
35 dfn[u]=low[u]=++cnt;
36 for(int i=head[u];~i;i=e[i].nextt){
37 int v=e[i].v;
38 if(!dfn[v]){
39 tarjan(v,u);
40 low[u]=min(low[u],low[v]);
41 if(low[v]>=dfn[u]){
42 if(u!=root)
43 cut[u]=true;
44 else
45 child++;
46 }
47 }
48 else if(v!=f)
49 low[u]=min(low[u],dfn[v]);
50 }
51 }
52 void dfs(int u){
53 vis[u]=liantong;
54 vnum++;
55 for(int i=head[u];~i;i=e[i].nextt){
56 int v=e[i].v;
57 if(cut[v]&&vis[v]!=liantong){
58 vis[v]=liantong;
59 cutnum++;
60 }
61 if(!vis[v])
62 dfs(v);
63 }
64 }
65 void addedge(int u,int v){
66 e[tot].v=v;
67 e[tot].nextt=head[u];
68 head[u]=tot++;
69 }
70 void init(){
71 memset(head,-1,sizeof(head));
72 tot=0;
73 cnt=0;
74 ans1=0;
75 ans2=1;
76 vnum=cutnum=0;
77 liantong=0;
78 n=0;
79 memset(vis,0,sizeof(vis));
80 memset(cut,0,sizeof(cut));
81 memset(dfn,0,sizeof(dfn));
82 memset(low,0,sizeof(low));
83 }
84 int main(){
85 int t=1;
86 while(cin>>m){
87 if(m==0)
88 break;
89 init();
90
91 while(m--){
92 int u,v;
93 cin>>u>>v;
94 addedge(u,v);
95 addedge(v,u);
96 n=max(u,max(n,v));
97 }
98
99 for(int i=1;i<=n;i++){
100 if(!dfn[i]){
101 child=0,root=i;
102 tarjan(i,i);
103 if(child>=2)
104 cut[i]=true;
105 }
106 }
107 for(int i=1;i<=n;i++){
108 if(!vis[i]&&!cut[i]){
109 ++liantong;
110 vnum=0,cutnum=0;
111 dfs(i);
112 //cout<<"!!"<<vnum<<endl;
113 if(cutnum==0){
114 ans1+=2;
115 ans2*=vnum*(vnum-1)/2;
116 }
117 else if(cutnum==1){
118 ans1+=1;
119 ans2*=vnum;
120 }
121 }
122 }
123 printf("Case %d: %lld %lld\n",t++,ans1,ans2);
124 }
125 return 0;
126 }
来源:https://www.cnblogs.com/starve/p/11055405.html
