Hdu 4738 Caocao‘s Bridges 割边(桥)

题意

给定n个兵营和m座桥,每座桥上有若干个敌人,要求炸掉最多一座桥使得n个兵营和m座桥连成的无向图被分为至少两个连通块。炸一座桥至少出动一名士兵并且出动的士兵个数不能小于桥上的敌人个数,桥上可能没有敌人。

思路

炸掉一座桥使得无向图变成2个以上的连通图。也就是从图中删除一条边e之后,图分裂为两个不相连的子图,那么e称为 或者 割边 。就是这题就是求割边的模板题了。具体算法链接跳转Tarjan算法与无向图连通性。
具体思路是求割边中权值最小的边,如果图本来就是2个以上的连通图输出答案0,如果不是那么输出割边中的权值最小值,注意这个最小值如果是0要输出1,因为至少要出动一名士兵去炸桥。代码如下:

#include
using namespace std;
const int maxn=1000005;
const int inf=0x3f3f3f3f;
int n,m;
int tot;
int head[1005],Next[maxn],ver[maxn],bridge[maxn],w[maxn];
//bridge[i]为1说明边i为割边
int dfn[1005],low[1005];//时间戳和追溯值
int deep;//当前时间戳
void init()//初始化
{
    for(int i=1;i<=n;i++)
    head[i]=0;
    memset(bridge,0,sizeof(bridge));
    memset(dfn,0,sizeof(dfn));
    tot=1;
    deep=0;
}

void add(int x,int y,int z)
{
    ver[++tot]=y,w[tot]=z,Next[tot]=head[x],head[x]=tot;
}

void tarjan(int x,int in_edge)//tarjan算法求割边
{
    dfn[x]=low[x]=++deep;
    for(int i=head[x];i;i=Next[i])
    {
        int y=ver[i];
        if(!dfn[y])
        {
            tarjan(y,i);
            low[x]=min(low[x],low[y]);

            if(dfn[x]<low[y])
            {
                bridge[i]=bridge[i^1]=1;
            }
        }else if(i!=(in_edge^1))
        {
            low[x]=min(low[x],dfn[y]);
        }
    }
}
int main()
{
    while(~scanf("%d%d",&n,&m)&&(m||n))
    {
        init();
        for(int i=1;i<=m;i++)//输入边
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
            add(y,x,z);
        }

        int num=0;
        int f=0;
        int ans=inf;
        for(int i=1;i<=n;i++)
        {
            if(!dfn[i])//tarjan算法求割边
            {
                num++;//num存储联通块个数
                tarjan(i,0);
            }
        }
        
        for(int i=1;i<=2*m;i++)
        {
            if(bridge[i])//在割边中找权值最小的割边
            {
                ans=min(ans,w[i]);
            }
        }

        if(num>=2)//连通块大于等于2说明不需要炸桥
        {
            printf("0\n");
        }else //需要炸桥,并且至少需要一个人
        {
            if(ans==inf)
            {
                printf("-1\n");
            }else
            printf("%d\n",max(ans,1));
        }
    }
return 0;
}

你可能感兴趣的:(算法,图论)