又做了一道求割点的题。
可以发现,如果boom处不在割点那么是没有影响的,所以我们只讨论割点的情况。
在求出所有的割点之后,整个图被分成了几个联通块。我们对联通块含有割点的个数进行讨论。
如果无割点,那么我们只需要建立两个出口,防止建立一个出口而这个出口炸掉。
如果有一个割点,我们必须建立一个出口(不能在割点处)。
如果有两个割点,我们不需要建立出口,因为一个爆炸时我们可以从另一个出去。
所以先tarjan求割点再dfs一下每个联通块就好了。
一开始vis数组弄了bool类型然而我用的是时间戳2333333333333。
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
int n,m,cnt,num,tot,deg,ans1,T,cases,root;
ll ans2;
int head[505],dfn[505],low[505],vis[505];
bool cut[505];
int next[1005],list[1005];
inline int read()
{
int a=0,f=1; char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
return a*f;
}
inline void insert(int x,int y)
{
next[++cnt]=head[x];
head[x]=cnt;
list[cnt]=y;
}
void tarjan(int x,int f)
{
dfn[x]=low[x]=++tot;
for (int i=head[x];i;i=next[i])
if (!dfn[list[i]])
{
tarjan(list[i],x);
low[x]=min(low[x],low[list[i]]);
if (low[list[i]]>=dfn[x])
{
if (x==root) deg++; else cut[x]=1;
}
}
else if (list[i]!=f) low[x]=min(low[x],dfn[list[i]]);
}
void dfs(int x)
{
vis[x]=T;
if (cut[x]) return;
cnt++;
for (int i=head[x];i;i=next[i])
{
if (cut[list[i]]&&vis[list[i]]!=T) num++,vis[list[i]]=T;
if (!vis[list[i]]) dfs(list[i]);
}
}
int main()
{
m=read();
while (m)
{
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));
cnt=tot=n=ans1=T=0; ans2=1;
for (int i=1;i<=m;i++)
{
int u=read(),v=read();
n=max(n,max(u,v));
insert(u,v); insert(v,u);
}
for (int i=1;i<=n;i++)
{
if (!dfn[i]) tarjan(root=i,0);
if (deg>=2) cut[root]=1;
deg=0;
}
for (int i=1;i<=n;i++)
if (!vis[i]&&!cut[i])
{
T++; cnt=num=0;
dfs(i);
if (!num) ans1+=2,ans2*=cnt*(cnt-1)/2;
if (num==1) ans1++,ans2*=cnt;
}
printf("Case %d: %d %lld\n",++cases,ans1,ans2);
m=read();
}
return 0;
}