几句话题解:

先跑Tarjan求点双统计每个点双有几个割点

2个及以上->安全

1个->非这个割点随便建个出口

没->建两个

组合数学瞎算一波

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<iterator>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include<queue>
#include<iomanip>
using namespace std;

struct ed
{
	int pre,to;
}edge[2010]={0};
int nodenum,edgenum,fx,tx,at=1,pointer[1010]={0};

int dfn[1010]={0},low[1010]={0},tstamp=0,sccnum=0;
bool ap[1010]={false};

long long nodev[1010]={0},nodec[1010]={0};
bool vis[1010]={false},got[1010]={false};

long long ansx=1,ansc=0,ansv=1;

inline void readx(int& x)
{
	x=0; int k=1; register char ch=0;
	while (ch<'0' || ch>'9') { ch=getchar(); if (ch=='-') k=-1; }
	while (ch>='0' && ch<='9') { x=x*10+ch-'0'; ch=getchar(); }
	x*=k;
}

inline void Insert()
{
	edge[at].pre=pointer[fx];
	edge[at].to=tx;
	pointer[fx]=at;
	at++;
	edge[at].pre=pointer[tx];
	edge[at].to=fx;
	pointer[tx]=at;
	at++;
}

void Tarjan(int u,int fatherx)
{
	dfn[u]=low[u]=++tstamp;
	int prex=pointer[u],chnum=0;
	while (prex)
	{
		if (!dfn[edge[prex].to])
		{
			chnum++;
			Tarjan(edge[prex].to,u);
			low[u]=min(low[u],low[edge[prex].to]);
			if (low[edge[prex].to]>=dfn[u]) ap[u]=true;
		}
		else if (edge[prex].to!=fatherx) low[u]=min(low[u],dfn[edge[prex].to]);
		prex=edge[prex].pre;
	}
	if (fatherx==-1 && chnum==1) ap[u]=false;
}

inline void dfs1(int nownode)
{
	int prex=pointer[nownode];
	nodec[sccnum]++; got[nownode]=true;
	while (prex)
	{
		if (!vis[edge[prex].to])
		{
			if (!ap[edge[prex].to])
			{
				vis[edge[prex].to]=true;
				dfs1(edge[prex].to);
			}
			else 
			{
				vis[edge[prex].to]=true;
				nodev[sccnum]++;
			}
		}
		prex=edge[prex].pre;
	}
}

int main()
{
	readx(edgenum);
	while (edgenum!=0)
	{
		at=ansx=1; ansc=tstamp=nodenum=sccnum=0;
		memset(dfn,0,sizeof(dfn));
		memset(low,0,sizeof(low));
		memset(nodec,0,sizeof(nodec));
		memset(nodev,0,sizeof(nodev));
		memset(edge,0,sizeof(edge));
		memset(pointer,0,sizeof(pointer));
		memset(ap,0,sizeof(ap));
		memset(got,0,sizeof(got));
		
		for (int i=1;i<=edgenum;i++)
		{
			readx(fx); readx(tx);
			nodenum=max(nodenum,max(fx,tx)); 
			Insert();
		}
		
		for (int i=1;i<=nodenum;i++) if (!dfn[i]) Tarjan(i,-1);
		
		for (int i=1;i<=nodenum;i++) if (!got[i] && !ap[i]) 
		{
			sccnum++; 
			memset(vis,0,sizeof(vis)); vis[i]=true;
			dfs1(i);
		}
		
		/*for (int i=1;i<=sccnum;i++) printf("%d %d\n",nodec[i],nodev[i]);
		for (int i=1;i<=nodenum;i++) printf("%d ",ap[i]); printf("\n");*/
		
		for (int i=1;i<=sccnum;i++)
		{
			if (!nodev[i]) 
			{
				ansx*=nodec[i]*(nodec[i]-1)/2;
				ansc+=2;
			}
			else if (nodev[i]==1) 
			{
				ansx*=nodec[i];
				ansc+=1;
			}
		}
		printf("Case %lld: %lld %lld\n",ansv,ansc,ansx);	
		readx(edgenum); ansv++;
	}
	return 0;
}