题目描述:曹操在长江上修了n个岛,m座桥,桥上有一定士兵把守。刘备派人去炸一座桥,使得避免所有岛屿连成一起。要求派出的人不少与桥上把守的士兵,问最少派多少人。

这是裸的割顶(割点)、割桥问题,找出所有的割桥,求最小值即可。

坑点:

1、重边问题,判断如果“割桥”有重边,那么其实不是割桥,不能考虑。

2、有可能一开始就不是所有的岛连接在一起,则不需要派人。

3、当割桥上士兵为0时,要派一个人去炸桥。

试验证明,以上情况都会出现,为我的漏洞百出的思维感到忧伤。。。。

代码:

#include<bits/stdc++.h>
#define N 1000+10
#define mem(f,n) memset(f,n,sizeof f)
using namespace std;
int low[N],pre[N],fr[N],i,j,k,l,n,m,t,h,cnt,dfs_clock,Ans;
short int vis[N][N];
bool iscut[N];

struct edge{    int u,w,la;   }G[200010];

int min(int a,int b) {return a>b?b:a;}

void addedge(int u,int v,int k)
{
    G[++cnt].u=v;
    G[cnt].w=k;
    G[cnt].la=fr[u];
    fr[u]=cnt;
}

int dfs(int u,int fa)
{
    int lowu=pre[u]=++dfs_clock;
    int child=0;
    for (int i=fr[u];i;i=G[i].la)
    {
        int v=G[i].u;
        if (!pre[v])
        {
            child++;
            int lowv=dfs(v,u);
            lowu=min(lowu,lowv);

            if (lowv>pre[u])                           //割桥
            {
                if (vis[u][v]>1)continue;
                Ans=min(Ans,G[i].w);
            }
        }
        else if (pre[v]<pre[u] && v!=fa)
        {
            lowu=min(lowu,pre[v]);
        }
    }
    if (fa<0 && child==1) iscut[u]=0;
    low[u]=lowu;
    return lowu;
}

int main()
{
    while (~scanf("%d%d",&n,&m)&& n>0)
    {
        Ans=1e7;
        dfs_clock=cnt=0;
        mem(pre,0);
        mem(G,0);
        mem(fr,0);
        mem(vis,0);
        for (i=1;i<=m;i++)
        {
            int l;
            scanf("%d%d%d",&j,&k,&l);
            addedge(j,k,l); vis[j][k]++;
            addedge(k,j,l); vis[k][j]++;
        }
        dfs(1,-1);
        if (dfs_clock<n)cout<<0<<endl;else
        if (Ans==10000000)puts("-1");else
        {
            if (Ans==0)cout<<1<<endl;else cout<<Ans<<endl;
        }
    }
    return 0;
}