备用交换机(割点)

n个城市之间有通讯网络,每个城市都有通讯交换机,直接或间接与其它城市连接。因电子设备容易损坏,需给通讯点配备备用交换机。但备用交换机数量有限,不能全部配备,只能给部分重要城市配置。于是规定:如果某个城市由于交换机损坏,不仅本城市通讯中断,还造成其它城市通讯中断,则配备备用交换机。请你根据城市线路情况,计算需配备备用交换机的城市个数,及需配备备用交换机城市的编号。

分析:无向图求割点。

求割点分两种情况:1,是根并且有超过一个孩子2,不是根,但是对于cur这个点来说,它的某一个孩子不管怎么样一定要经过cur才能到cur之前的点,说明cur是割点,具体操作是引入时间戳,d[i]记录第几个被访问到,low[i]记录在经过不是父亲的点时能到达的最小的d[i]。

注意概念:删除一条边仍然连通=边双连通=不含割边(所以如果flag数组都为0,说明是边双连通)

AC代码

#include <stdio.h>
#include <string.h>
int s[55][55];
int root;
int sum;
int flag[15];
int low[15];
int d[15];
int time;
int n;
int min(int a,int b)
{
    return a<b?a:b;
}
void dfs(int cur,int father)
{
    int child=0,i;
    low[cur]=d[cur]=time++;
    for (i=1;i<=n;i++)
    {
        if (s[i][cur]==1)
        {
            if (d[i]==0)
              {
                child++;
                dfs(i,cur);
                low[cur]=min(low[cur],low[i]);
            if ((cur!=root)&&(low[i]>=d[cur]))//如果i的最低深度大于等于cur的到达时间,说明不管怎么从i到cur之前的总要经过cur,所以cur是割点
                        {
                            flag[cur]=1;
                            sum++;
                        }
            if ((cur==root)&&(child==2))//如果cur是根,并且孩子数大于1
                        {
                            flag[cur]=1;
                            sum++;
                        }
                }
              else
            if (i!=father)
            low[cur]=min(low[cur],d[i]);
          }
    }
    return;

}
 int main()
 {
     int a,b,i,j;
     freopen("gd.in","r",stdin);
     freopen("gd.out","w",stdout);
     scanf("%d",&n);
     for (i=1;i<=n;i++)
        for (j=1;j<=n;j++)
        s[i][j]=0;
        while(scanf("%d%d",&a,&b)==2)
        {
            s[a][b]=1;
            s[b][a]=1;
        }
        root=1;
        memset(flag,0,sizeof(flag));
        memset(d,0,sizeof(d));
        sum=0;
        time=1;
        dfs(1,root);
        printf("%d\n",sum);
        for (i=1;i<=n;i++)
        if (flag[i]==1)
        printf("%d\n",i);
        return 0;
 }




你可能感兴趣的:(备用交换机(割点))