比赛 |
不准粘代码,必须自己写(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;
}