
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include<bits/stdc++.h>
using namespace std;
const int maxn = 500005;
#define int long long
int dfn[maxn], low[maxn];
vector <int> g[maxn];
bool vis[maxn];
bool vis2[maxn];
int cut[maxn];
int t, sccnum;
int root;
inline int read() {
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') {
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
inline void write(int x) {
if (x < 0) {
x = ~(x - 1);
putchar('-');
}
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
inline void tarjan(int u){
dfn[u] = low[u] = ++t;
int flag = 0;
for(int i = 0; i < g[u].size(); i++){
int v = g[u][i];
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u]){
flag++;
if(u != root or flag > 1) cut[u] = 1;
}
}
else low[u] = min(low[u], dfn[v]);
}
}
inline bool iscut(int u){
if(cut[u]) return 1;
vis[u] = 1;
bool f = false;
for(int v = 0; v < g[u].size(); v++){
if(!vis[g[u][v]]) {
if(iscut(g[u][v])) f = true;
}
}
return f;
}
inline int dfs(int u){
int cnt = 1;
vis2[u] = 1;
for(int v = 0; v < g[u].size(); v++){
if(!vis2[g[u][v]]) cnt += dfs(g[u][v]);
}
return cnt;
}
signed main(){
int ttt = 0;
while(1){
int n = read();
if(n == 0) break;
int MAXN = -1;
int m = n;
for(int i = 1; i <= m; i++){
int u = read(), v = read();
g[u].push_back(v);
g[v].push_back(u);
MAXN = max(MAXN, max(u, v));
}
for(int i = 1; i <= n; i++){
if(!dfn[i]) root = i, tarjan(i);
}
int ret = 0;
long long ans = 1;
int ans2 = 0;
bool f = true;
for(int i = 1; i <= n; i++){
if(cut[i]){
memset(vis, 0, sizeof(vis));
memset(vis2, 0, sizeof(vis2));
f = 0;
for(int j = 0; j < g[i].size(); j++){
vis[i] = 1;
if(!iscut(g[i][j])){
vis2[i] = 1;
if(!vis2[g[i][j]]) ans2 += 1;
ans *= dfs(g[i][j]);
}
}
}
}
printf("Case %lld: ", ++ttt);
for(int i = 1; i <= n; i++){
g[i].clear();
}
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(cut, 0, sizeof(cut));
memset(vis, 0, sizeof(vis));
memset(vis2, 0, sizeof(vis2));
t = 0, sccnum = 0, root = 0;
if(f){
printf("2 %lld\n", (MAXN-1)*MAXN/2);
continue;
}
printf("%lld %lld\n", ans2, ans);
}
return 0;
}