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 ",t++,ans1,ans2); 124 } 125 return 0; 126 }