把割点删去后,剩下的联通块个数就是答案,方案数就是siz乘一起,但要讨论一些特殊情况,没有割点时答案直接算,一个联通块如果连接多个割点是不需算入答案的;
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; typedef long long ll; const int maxn=505; struct edg{ int nxt,u,v; }e[maxn<<1]; int dfn[maxn],low[maxn],ind,is[maxn]; int last[maxn],t,cas,n,m,vis[maxn],cc,tim; ll ans=1,sum,cnt,tmp,w[maxn]; void add(int x,int y){ n=max(n,max(x,y)); ++t;e[t].nxt=last[x];last[x]=t;e[t].v=y; } void dfs(int x,int fa){ low[x]=dfn[x]=++ind; int child=0; for(int i=last[x];i;i=e[i].nxt){ int v=e[i].v; if(v==fa)continue; if(!dfn[v]){ child++; dfs(v,x); low[x]=min(low[x],low[v]); if(fa&&low[v]>=dfn[x]){is[x]=1;++cc;} if(child>1&&!fa){is[x]=1;++cc;} } else low[x]=min(low[x],dfn[v]); } } int solve(int x){ vis[x]=1; int siz=1; for(int i=last[x];i;i=e[i].nxt){ int v=e[i].v; if(!vis[v]){ if(is[v]){ if(w[v]!=tim){cnt++;w[v]=tim;} } else siz+=solve(v); } } return siz; } int main(){ while(scanf("%d",&m)!=EOF&&m){ printf("Case %d: ",++cas); memset(last,0,sizeof(last)); memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(vis,0,sizeof(vis)); memset(is,0,sizeof(is)); cc=tim=sum=n=t=ind=0;ans=1; int x,y; for(int i=1;i<=m;++i){ scanf("%d%d",&x,&y); add(x,y);add(y,x); } for(int i=1;i<=n;++i){ if(!dfn[i])dfs(i,0); } if(!cc){printf("2 %d\n",n*(n-1)/2);continue;} for(int i=1;i<=n;++i) if((!vis[i])&&(!is[i])){ ++tim; cnt=0; int tmp=solve(i); //cout<<cnt<<' '<<tmp<<endl; if(cnt<=1){ sum++; ans*=tmp; } } printf("%lld %lld\n",sum,ans); } return 0; }