可以说是很好的一道点双连通例题了
那我们暂时把所有割点删掉,这样分成了若干个连通块
为什么肯定符合要求呢?
但是答案不是最小的
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=5009;
struct edge{
int to,nxt,use;
}d[maxn]; int head[maxn],cnt;
void add(int u,int v){d[++cnt]=(edge){v,head[u],0},head[u]=cnt; }
int dfn[maxn],low[maxn],id,vis[maxn],cut[maxn],stac[maxn],top,bccnum;
vector<int>bcc[maxn];
int ans1,ans2=1,n,m;
void tarjan(int u,int fa)
{
int child=0;
dfn[u]=low[u]=++id, stac[++top]=u;
for(int i=head[u];i;i=d[i].nxt )
{
int v=d[i].to;
if( !dfn[v] )
{
tarjan(v,fa);
low[u]=min( low[v],low[u] );
if( low[v]>=dfn[u] )
{
child++;
if( u!=fa||child>=2 ) cut[u]=1;
bcc[++bccnum].clear();
/*while( stac[top]!=u )
bcc[bccnum].push_back( stac[top--] );*/
int temp;
while( temp=stac[top--] )
{
bcc[bccnum].push_back(temp);
if( temp==v ) break;
}
if( stac[top]!=u ) cout << "去死吧\n" << top << endl;
bcc[bccnum].push_back(u);//割点不能出栈,因为可能包含在多个点双里
}
}
else low[u]=min( low[u],dfn[v] );
}
}
void init()
{
cnt=1,bccnum=0,id=0,top=0;
ans1=0,ans2=1;
for(int i=0;i<=n;i++) head[i]=low[i]=dfn[i]=cut[i]=0;
n=0;
}
signed main()
{
int casenum=0;
while( cin >> m && m )
{
for(int i=1;i<=m;i++)
{
int l,r; cin >> l >> r;
add(l,r); add(r,l);
n=max( max(l,r),n );
}
for(int i=1;i<=n;i++)
if( !dfn[i] ) tarjan(i,i);
for(int i=1;i<=bccnum;i++)
{
int cu=0,num=bcc[i].size();
for(int j=0;j<num;j++)
if( cut[bcc[i][j]] ) cu++;
if( !cu ) ans1+=2,ans2*=num*(num-1)/2;
if( cu==1 ) ans1++,ans2*=(num-1);
}
printf("Case %lld: %lld %lld\n",++casenum,ans1,ans2);
init();
}
}