刘汝佳新书
题意:求无向图的点双连通分量,当一个点双连通分量只有一个割顶时才需要安装太平井且任选一个非割顶安装太平井即可。
View Code
#include <cstdio> #include <iostream> #include <vector> #include <stack> #include <cstring> #include <map> using namespace std; #define MAXN 60000 int n; vector<int> G[MAXN],bcc[MAXN]; int pre[MAXN],iscut[MAXN]; int bccno[MAXN]; int dfs_clock,bcc_cnt; struct Edge{ int u,v; Edge(int a,int b) { u=a,v=b; }; }; stack<Edge> S; int dfs(int u,int fa) { int lowu= pre[u]=++dfs_clock; int child=0; for(int i=0;i<G[u].size();i++) { int v=G[u][i]; Edge e=Edge(u,v); if(!pre[v]) { child++; S.push(e); int lowv=dfs(v,u); lowu=min(lowu,lowv); if(lowv>=pre[u]) { iscut[u]=1; bcc_cnt++; bcc[bcc_cnt].clear(); for(;;) { Edge a=S.top(); S.pop(); if(bcc_cnt!=bccno[a.u]) { bcc[bcc_cnt].push_back(a.u); bccno[a.u]=bcc_cnt; } if(bcc_cnt!=bccno[a.v]) { bcc[bcc_cnt].push_back(a.v); bccno[a.v]=bcc_cnt; } if(a.v==v&&a.u==u) break; } } } else if(pre[v]<pre[u]&&v!=fa) { S.push(e); lowu=min(pre[v],lowu); } } if(child==1&&fa<0) iscut[u]=0; return lowu; } void find_bcc(int N) { memset(iscut,0,sizeof(iscut)); memset(pre,0,sizeof(pre)); memset(bccno,0,sizeof(bccno)); dfs_clock=0; bcc_cnt=0; for(int i=0;i<N;i++) if(!pre[i]) dfs(i,-1); } int main() { int cas=0; while(~scanf("%d",&n)) { if(n==0) break; int a,b; for(int i=0;i<MAXN;i++) G[i].clear(); map<int,int> m; int N=0; for(int i=0;i<n;i++) { scanf("%d%d",&a,&b); // a--,b--; if(m.count(a)==0) m[a]=N++; if(!m.count(b)) m[b]=N++; G[m[a]].push_back(m[b]); G[m[b]].push_back(m[a]); } find_bcc(N); long long ans1=0,ans2=1; for(int i=1;i<=bcc_cnt;i++) { int cnt=0; for(int j=0;j<bcc[i].size();j++) { if(iscut[bcc[i][j]]) cnt++; } if(cnt==1) { ans1++; ans2*=(bcc[i].size()-cnt); } } if(bcc_cnt==1) { ans1=2; ans2=(bcc[1].size()*(bcc[1].size()-1))/2; } printf("Case %d: %lld %lld\n",++cas,ans1,ans2); } }