比赛 不准粘代码,必须自己写(HS除外) 评测结果 AAAAAAAAAA
题目名称 矿场搭建 最终得分 100
用户昵称 瑆の時間~無盡輪迴·林蔭 运行时间 0.006 s
代码语言 C++ 内存使用 13.68 MiB
提交时间 2019-09-23 20:12:21
显示代码纯文本
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
bool Cut[501];
int dfn[501],low[501],vis[501],head[501];
long long int num,cnt,root,Time,rs,n,m,ans1,ans2,CASE,greap,cut;
struct Node
{
	int v,next;
};
Node e[1001];
void Add(int u,int v)
{
	e[++cnt].v=v;
	e[cnt].next=head[u];
	head[u]=cnt;
}
void TARJAN(int u,int fa)
{
	//TARJAN求联通块 
	dfn[u]=low[u]=++Time;
	for(int i=head[u];i;i=e[i].next)
	{
		int v=e[i].v;
		if(!dfn[v])
		{
			TARJAN(v,u);
			low[u]=min(low[v],low[u]);
			if(low[v]>=dfn[u])
			{
				if(u!=root)
				{
					Cut[u]=1;
				}
				else
					rs++;
			}
		}
		else
			if(v!=fa)
			{	
				low[u]=min(low[u],dfn[v]);
			}
	}
}
void  dfs(int u)
{
	int v;
	vis[u]=greap;
	num++;
	for(int i=head[u];i;i=e[i].next)
	{
		v=e[i].v;
		if(Cut[v]&&vis[v]!=greap)
		{
			cut++;
			vis[v]=greap;
		}
		if(!vis[v])
		{
			dfs(v);
		}
	}
}
void csh()
{
       memset(head,0,sizeof(head));
       memset(dfn,0,sizeof(dfn));
       memset(low,0,sizeof(low));
       memset(Cut,0,sizeof(Cut));
       memset(vis,0,sizeof(vis));
       Time=cnt=n=ans1=greap=0;
       ans2=1;
} 
int main()
{
	freopen("bzoj_2730.in","r",stdin);
	freopen("bzoj_2730.out","w",stdout);
	long long int u,v;
	CASE=1;
	while(cin>>m&&m)
	{
		csh();
		for(int i=1;i<=m;i++)
		{
			scanf("%lld%lld",&u,&v);
			Add(u,v);
			Add(v,u);
			n=max(n,v);
			n=max(n,u);
		}
		for(int i=1;i<=n;i++)
		{
			if(dfn[i]==0)
			{
				root=i;
				rs=0;
				TARJAN(i,i);
				if(rs>=2)
				{
					Cut[i]=1;
				} 
			}
		}
		for(int i=1;i<=n;i++)
		{
			if(!vis[i]&&!Cut[i])
			{
				++greap;
				num=cut=0;
				dfs(i);
				if(cut==0)
				{//一个双连通分量中只需要设置一个点
				//,就可以满足这个分量里的点能够跑到这个出口来。
				//同上,我们还要考虑出口坍塌的情况。
				//在这里,因为只会坍塌一个点,所以如果出口坍塌了,
				//割点就不会坍塌,这个分量中的其他点可以通过割点跑到另外的双连通分量中,
				//此时等价于同一个双连通分量。
					ans1+=2;
					ans2*=(num-1)*num/2;
				}
				if(cut==1)
				{
					//如果这个分组只有一个割点
					//只需要在分组内设立一个出口 
					//可以设立在任意一个非割点的地方 
					ans1+=1;
					ans2*=num;
				}
				if(cut>=2)
				{
					//如果有两个及以上个割点,则无需建立,可以直接到达其他联通块 
				}
			}
		}
		cout<<"Case "<<CASE++<<": "<<ans1<<" "<<ans2<<endl;//输出结果     
	}
	return 0;
}