#include <bits/stdc++.h> using namespace std; typedef unsigned long long ULL; const int N=1005; const int M=1005; int n, m; int head[N], E=0; // graph int dfn[N], low[N], ts=0; // tarjan stack<int> st; bool vis[N]; int ebcc_cnt; vector<int> ebcc[N]; // 存储每个双连通分量中有哪些点 bool cut[N]; // 判断该点是否为割点 int root; // 特判root节点 struct Edge{int v, ne;}e[M]; inline void add(int a, int b){ e[E].v=b; e[E].ne=head[a]; head[a]=E++; } void tarjan(int u){ dfn[u]=low[u]=++ts; st.push(u); if(u==root && head[u]==-1){ ebcc_cnt++; ebcc[ebcc_cnt].push_back(u); return; } int cnt=0; // 子树的数量 for(int i=head[u]; ~i; i=e[i].ne){ int v=e[i].v; if(!dfn[v]){ tarjan(v); low[u]=min(low[u], low[v]); if(dfn[u]<=low[v]){ // 割点判断条件 ++cnt; if(u!=root || cnt>1) cut[u]=true; ++ebcc_cnt; int j; do{ j=st.top(); st.pop(); ebcc[ebcc_cnt].push_back(j); }while(j!=v); ebcc[ebcc_cnt].push_back(u); } } else low[u]=min(low[u], dfn[v]); } } int main(){ int kase=1; while(cin>>m, m){ for(int i=1; i<=ebcc_cnt; ++i) ebcc[i].clear(); E=n=ts=ebcc_cnt=0; memset(head, -1, sizeof head); memset(dfn, 0x00, sizeof dfn); memset(cut, 0x00, sizeof cut); while(m--){ int a, b; cin>>a>>b; n=max(n, a), n=max(n, b); // 得到所有点的数量 add(a, b); add(b, a); } for(root=1; root<=n; ++root){ if(!dfn[root]) tarjan(root); } int res=0; // 需要放置的救援点的数量 ULL ans=1; // 放置救援点的方案数 // 分类讨论 for(int i=1; i<=ebcc_cnt; ++i){ int cnt=0; // 统计割点的数量 for(int j=0; j<ebcc[i].size(); ++j) if(cut[ebcc[i][j]]) ++cnt; // 一个BCC if(!cnt){ if(ebcc[i].size()>1){ res+=2; ans*=ebcc[i].size()*(ebcc[i].size()-1)/2; } else ++res; } // BCC有一个割点, 需要在BCC内部放一个救援点 else if(cnt==1){ ++res; ans*=ebcc[i].size()-1; } } cout<<"Case "<<kase++<<": "<<res<<" "<<ans<<endl; } return 0; }