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 }