先tarjan找割點和點雙連通份量,而後對一個點雙,若是沒有割點,那麼須要創建兩個出口(割掉一個另外一個備用);若是隻有一個割點,出口能夠設立在任意一個非割點的地方;若是有兩個及以上個割點,就不用建出口(能夠直接到達其餘聯通塊)ios
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=1005; int n,m,h[N],cnt,cas,ans1,dfn[N],low[N],tot,bl[N],s[N],top; long long ans2; struct qwe { int ne,to; }e[N]; int read() { int r=0,f=1; char p=getchar(); while(p>'9'||p<'0') { if(p=='-') f=-1; p=getchar(); } while(p>='0'&&p<='9') { r=r*10+p-48; p=getchar(); } return r*f; } void add(int u,int v) { cnt++; e[cnt].ne=h[u]; e[cnt].to=v; h[u]=cnt; } void tarjan(int u) { dfn[u]=low[u]=++tot; for(int i=h[u];i;i=e[i].ne) { if(dfn[e[i].to]) low[u]=min(low[u],dfn[e[i].to]); else { tarjan(e[i].to); low[u]=min(low[u],low[e[i].to]); if(low[e[i].to]>=dfn[u]) bl[u]++; } } } void tarjan2(int u) { dfn[u]=low[u]=++tot; s[++top]=u; for(int i=h[u];i;i=e[i].ne) { if(dfn[e[i].to]) low[u]=min(low[u],dfn[e[i].to]); else { tarjan2(e[i].to); low[u]=min(low[u],low[e[i].to]); if(low[e[i].to]>=dfn[u]) { int t,temp=0,size=0; do { t=s[top--]; if(bl[t]>=2) ++temp; ++size; } while(t!=e[i].to); t=u; if(bl[t]>=2) ++temp; ++size; if(!temp) ans1+=2,ans2*=size*(size-1)/2; else if(temp==1) ans1++,ans2*=size-1; } } } } int main() { while(1) { m=read(); if(!m) break; memset(h,0,sizeof(h)); memset(dfn,0,sizeof(dfn)); memset(bl,0,sizeof(bl)); cnt=1;n=0;ans1=0;ans2=1; for(int i=1;i<=m;i++) { int x=read(),y=read(); n=max(n,max(x,y)); add(x,y),add(y,x); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); else bl[i]++; memset(dfn,0,sizeof(dfn)); for(int i=1;i<=n;i++) if(!dfn[i]) tarjan2(i); printf("Case %d: %d %lld\n",++cas,ans1,ans2); } return 0; }