如果没有割点,任意选两个点建立出口。答案是2 C(n,2);
如果有割点,用搜索去跑,得出所有的连通块,如果一个连通块与超过1个割点相连,就需要建立一个出口,算有多少种情况 就是乘法计算原理。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
struct node{
int to;
int next;
node(){
}
node(int a,int b):to(a),next(b){
}
}edge[1005];
int head[1005];
int dfn[1005],low[1005],vis[1005],iscut[1005];
int root;
int tot ,ti;
void add_edge(int a,int b){
edge[tot] = node(b,head[a]);
head[a] = tot++;
edge[tot] = node(a,head[b]);
head[b] = tot++;
}
void tarjan(int u,int fa)
{
dfn[u] = ++ti;
low[u] = ti;
vis[u] = 1;
int k = 0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v = edge[i].to;
if(!vis[v])
{
k++;
tarjan(v,u);
low[u] = min(low[u],low[v]);
}
else if(v!=fa)
{
low[u] = min(low[u],dfn[v]);
}
if(u==root&&k>=2) iscut[u] = 1;
if(u!=root&&low[v]>=dfn[u]) iscut[u] = 1;
}
}
int size=0 ,cnt;
void dfs(int u,int t)
{
vis[u] = 1;
size++;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v = edge[i].to;
if(!vis[v]&&!iscut[v]) dfs(v,t);
else if(iscut[v]&&vis[v]<t) vis[v] = t,cnt++;
}
}
int main()
{
int u,v;
int t = 1;
while(scanf("%d",&m))
{
if(m==0) break;
n = 0;
memset(head,-1,sizeof(head));
tot = 0;
ti = 0;
for(int i=0;i<m;i++)
{
scanf("%d%d",&u,&v);
add_edge(u,v);
n = max(n,u);
n = max(n,v);
}
memset(dfn,0,sizeof(dfn));
memset(vis,0,sizeof(vis));
memset(low,0,sizeof(low));
memset(iscut,0,sizeof(iscut));
for(int i=1;i<=n;i++)
if(!dfn[i]) root = i,tarjan(i,-1);
memset(vis,0,sizeof(vis));
int ret = 0;
int ans=0;
long long cans=1;
for(int i=1;i<=n;i++)
{
if(!iscut[i]&&!vis[i])
{
cnt = 0;
size = 0;
dfs(i,i);
if(cnt<2) ans++,cans*=size;
}
else if(iscut[i]) ret ++;
}
printf("Case %d: ",t++);
if(ret==0){
printf("%d %llu\n",2,n*(n-1)/2);
}
else
{
printf("%d %llu\n",ans,cans);
}
}
return 0;
}