中午又水了一发

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2730

想一想,如果删除的点恰好是割点,那么就需要在割点两边各找一个安全通道,但是如果将图中所有割点删去后,发现一个联通块有两个或以上个割点,那么这个块内不需要建通道,因为一个割点删去后,人可以从别的路到其他联通块。

所以删去割点后,枚举所有只与一个割点相连的块,利用将其中点数相乘即可。

如果没有割点,那么要修两个通道,(n-1)*n/2种方案。

代码凌乱:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int n,m;
int v[1501]={},pr[1501]={},num,bia[1501]={};
bool cut[1501]={},vis[1501]={};
inline void add(int l,int r)
{
     v[num]=r;
     pr[num]=bia[l];bia[l]=num;
     num++;
     v[num]=l;
     pr[num]=bia[r];bia[r]=num;
     num++;
}
int low[1501]={},dfn[1501]={},clo=0;
int son[1501]={};
void tarjan (int u,int fa)
{
     low[u]=dfn[u]=++clo;
     int i,r;son[u]=0;
     for (i=bia[u];i!=-1;i=pr[i])
     {
         r=v[i];
         if (!dfn[r])
         {
             tarjan(r,u);son[u]++;
             if (low[r]<low[u]) low[u]=low[r];
             if (dfn[u]<=low[r]&&fa!=-1) cut[u]=true;
         }
         else
           if (dfn[r]<dfn[u]&&low[u]>low[r])
           low[u]=low[r];
     }
     if (son[u]>1&&fa==-1) cut[u]=true;
}
int lia[1501]={},color,nco[1501]={};
int mar[1501]={};
void dfs(int u)
{
     vis[u]=true;
     int i,r;nco[color]++;
     for (i=bia[u];i!=-1;i=pr[i])
     {
         r=v[i];
         if (vis[r]) continue;
         if (!cut[r]) dfs(r);
         else
         {
             if (mar[r]!=color) mar[r]=color,lia[color]++;
         }
     }
}
inline void init()
{
     memset(bia,-1,sizeof(bia));
    memset(nco,0,sizeof(nco));
    memset(mar,0,sizeof(mar));
    memset(lia,0,sizeof(lia));
    memset(cut,false,sizeof(cut));
    memset(vis,false,sizeof(vis));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    num=color=clo=n=0;
}
int main()
{
    int i,j,l,r,xxx=0;
    while (1)
    {
    init();
    scanf("%d",&m);
    if (m==0) break;xxx++;
    for (i=1;i<=m;i++)
    {
        scanf("%d%d",&l,&r);
        if (l==-1) break;
        add(l,r);
        n=max(l,n);n=max(r,n);
    }
    for (i=1;i<=n;i++)
    {
        if (!dfn[i]) tarjan(i,-1);
    }
    int ans=0;
    long long hee=1ll;
    for (i=1;i<=n;i++)
    {
        if (!cut[i]&&!vis[i])
        {
           color++;dfs(i);
           if (lia[color]==1) ans++,hee*=nco[color];
        }
    }
    if (color==1) ans=2,hee=n*(n-1)/2;
    cout<<"Case "<<xxx<<": "<<ans<<" "<<hee<<endl;
    }
       
       
      
    return 0;
}
View Code