1 /* 2 LA5135图论 3 割点性质运用 4 5 关键:割顶出设置逃生点是不划算的。 6 这道题的思路算是比较简单,没有推导证明的成分,是BCC性质的运用 7 注意,当整张图是BCC时,至少要设置两个逃生点,这个也算是考点,开始没想到,下次注意 8 */ 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <math.h> 13 #include <ctype.h> 14 #include <string> 15 #include <iostream> 16 #include <sstream> 17 #include <vector> 18 #include <queue> 19 #include <stack> 20 #include <map> 21 #include <list> 22 #include <set> 23 #include <algorithm> 24 #define rec(i,n) for(int i=1;i<=n;i++) 25 #define INF 0x3f3f3f3f 26 using namespace std; 27 28 const int maxn = 101000 ; 29 struct edge 30 { 31 int u,v,cap,pre;//cap表示花费 32 edge(int u=0,int v=0):u(u),v(v){} 33 }Edge[maxn];//注意开两倍的边 34 int head[maxn],next[maxn],nedge;//表示读入的边的个数 35 void addedge(int u,int v) 36 { 37 Edge[++nedge]=edge(u,v);//边从1开始编号 38 next[nedge]=head[u]; 39 head[u]=nedge; 40 } 41 void edgeinit()//添边之前要初始化 42 { 43 nedge=0; 44 memset(head,-1,sizeof(head)); 45 } 46 int pre[maxn],iscut[maxn],bccno[maxn],dfs_clock,bcc_cnt; 47 vector<int> bcc[maxn]; 48 stack<edge>S ; 49 50 int dfs(int u,int fa) 51 { 52 int lowu=pre[u]=++dfs_clock; 53 int child=0; 54 for(int i=head[u];i!=-1;i=next[i]) 55 { 56 int v=Edge[i].v; 57 edge e=(edge){u,v}; 58 if (!pre[v]) 59 { 60 S.push(e); 61 child++; 62 int lowv=dfs(v,u);//这时,u是父节点 63 lowu=min(lowu,lowv); 64 if (lowv>=pre[u]) 65 { 66 iscut[u]=true; 67 bcc_cnt++;bcc[bcc_cnt].clear(); 68 for(;;) 69 { 70 edge x=S.top();S.pop(); 71 if(bccno[x.u]!=bcc_cnt){bcc[bcc_cnt].push_back(x.u);bccno[x.u]=bcc_cnt;} 72 if(bccno[x.v]!=bcc_cnt){bcc[bcc_cnt].push_back(x.v);bccno[x.v]=bcc_cnt;} 73 if(x.u==u&&x.v==v) break; 74 } 75 } 76 } 77 else if (pre[v]<pre[u] && v!=fa) 78 { 79 S.push(e); 80 lowu=min(lowu,pre[v]); 81 } 82 } 83 if(fa<0 && child==1) iscut[u]=0; 84 return lowu; 85 } 86 87 void find_bcc(int n)//n是定点个数 88 { 89 memset(pre,0,sizeof(pre)); 90 memset(iscut,0,sizeof(iscut)); 91 memset(bccno,0,sizeof(bccno)); 92 dfs_clock=bcc_cnt=0; 93 for(int i=1;i<=n;i++) 94 { 95 if(!pre[i]) dfs(i,-1); 96 } 97 } 98 void solve(int cas,int m) 99 { 100 long long n1=0,n2=1; 101 if (bcc_cnt==1) n1=2,n2=(long long)bcc[1].size()*(bcc[1].size()-1)/2; 102 else 103 { 104 for(int i=1;i<=bcc_cnt;i++)//枚举每个bcc 105 { 106 int cnt=0;//一个bcc中割顶的个数是1或0 107 for(int j=0;j<bcc[i].size();j++) 108 if(iscut[bcc[i][j]]) cnt++; 109 if(cnt==1) n1++,n2=n2*(long long)(bcc[i].size()-1); 110 } 111 } 112 cout<<"Case "<<cas<<": "<<n1<<" "<<n2<<endl; 113 return; 114 } 115 int main() 116 { 117 int n,cas=0; 118 119 while(cin>>n && n!=0) 120 { 121 cas++; 122 edgeinit(); 123 int m=0; 124 for(int i=1;i<=n;i++) 125 { 126 int u,v; 127 cin>>u>>v; 128 addedge(u,v);addedge(v,u); 129 m=max(m,u);m=max(m,v);//最大的点 130 } 131 find_bcc(m); 132 solve(cas,m); 133 } 134 return 0; 135 }