原题走这里
又是一道神奇的题
首先我们会发现在同一个双联通分量内
如果坍塌的不是割点则不会有任何影响
那么我们只考虑割点坍塌的情况
如果某个双连通分量有多于一个割点,则无需设置逃生出口
否则要在非割点的点上设置一个
每个设置了逃生出口双联通分量的大小减去1之后全部乘起来即可
注意特判全图只有一个双联通分量的情况,只需2个逃生出口
代码如下:
#include
using namespace std;
int k,m,n,s[1011],t[1011],a[1011],dfn[1011],low[1011],head[1011],dfs_clock,top,b[1011],iscut[1011];
struct edge
{
int v,p;
}e[1010];
inline void addedge(int u,int v)
{
e[++top]=(edge){v,head[u]};
head[u]=top;
e[++top]=(edge){u,head[v]};
head[v]=top;
}
void dfs1(int u,int fa,bool isroot=0)
{
dfn[u]=low[u]=++dfs_clock;
int son_num=0;
bool flag=0;
for(int i=head[u];i;i=e[i].p)
{
int v=e[i].v;
if(v==fa)continue;
if(dfn[v])
{
low[u]=min(low[u],dfn[v]);
}
else
{
dfs1(v,u,0);
low[u]=min(low[u],low[v]);
son_num++;
if((!isroot)&&low[v]>=dfn[u])flag=1;
}
}
if(isroot&&son_num>1)flag=1;
if(flag)iscut[u]=1;
}
int dfs2(int u,int &temp)
{
if(b[u])return 0;
b[u]=1;
if(iscut[u])
{
temp++;
return 0;
}
int ret=1;
for(int i=head[u];i;i=e[i].p)
{
ret+=dfs2(e[i].v,temp);
}
return ret;
}
int main()
{
freopen("bzoj_2730.in","r",stdin);
freopen("bzoj_2730.out","w",stdout);
while(cin>>m)
{
if(!m)return 0;
k++;
top=0;
memset(head,0,sizeof(head));
memset(b,0,sizeof(b));
memset(iscut,0,sizeof(iscut));
memset(dfn,0,sizeof(dfn));
for(int i=1;i<=m;i++)
{
cin>>s[i]>>t[i];
a[2*i-1]=s[i];
a[2*i]=t[i];
}
sort(a+1,a+2*m+1);
int n=unique(a+1,a+2*m+1)-(a+1);
for(int i=1;i<=m;i++)
{
addedge(lower_bound(a+1,a+n+1,s[i])-a,lower_bound(a+1,a+n+1,t[i])-a);
}
int ret=0;
unsigned long long pro_ret=1;
for(int i=1;i<=n;i++)
{
dfs_clock=0;
if(!dfn[i])dfs1(i,0,1);
}
int flag=0;
for(int i=1;i<=n;i++)
{
if((!b[i])&&(!iscut[i]))
{
int temp=0;
unsigned long long pro=dfs2(i,temp);
if(temp<=1)
{
ret++;
pro_ret*=pro;
}
for(int i=1;i<=n;i++)
{
if(iscut[i])b[i]=0;
}
}
if(iscut[i])flag=1;
}
if(flag)cout<<"Case "<": "<' '<else cout<<"Case "<": "<<2<<' '<1)/2<