HDU4738Caocao's Bridges(无向图求桥)

题目:

  曹操在长江上建立了一些点,点之间有一些边连着。如果这些点构成的无向图变成了连通图,那么曹操就无敌了。刘备为了防止曹操变得无敌,就打算去摧毁连接曹操的点的桥。但是诸葛亮把所有炸弹都带走了,只留下一枚给刘备。所以刘备只能炸一条桥。

  题目给出n,m。表示有n个点,m条桥。

  接下来的m行每行给出a,b,c,表示a点和b点之间有一条桥,而且曹操派了c个人去守卫这条桥。

 

  现在问刘备最少派多少人去炸桥。

  如果无法使曹操的点成为多个连通图,则输出-1.


思路:

  就是用tarjan算法算出桥,再比较哪一个的值最小。

 

Tips:

  注意三点:

  ①. 有重边,所以tarjan算法要处理重边。有两种处理方法,一种是先把所有的边存下,发现两点有重边的时候就只给这两个点连一条权值为无穷大的边。或者是在tarjan算法里处理重边,即使之求u或u的子树能够追溯到的最早的栈中节点的次序号时可访问父节点的次序号。

  ②. 如果无向图图本身已经有两个连通图了,就无需派人去炸桥,这时候输出0。

  ③. 如果求出来的最小权值桥的守卫人数为0时,也需要派出一个人去炸桥。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAXN = 1005;
struct Edge
{
    int v, w, nxt;
    Edge(){}
    Edge(int _v, int _w, int _nxt):v(_v), w(_w), nxt(_nxt){}
}edge[MAXN*MAXN];
int n, m, cnt, sum, dep, top, scc;
int head[MAXN], dfn[MAXN], low[MAXN], belong[MAXN], Stack[MAXN];
void addedge(int u, int v, int w)
{
    edge[cnt] = Edge(v, w, head[u]);
    head[u] = cnt++;

    edge[cnt] = Edge(u, w, head[v]);
    head[v] = cnt++;
}
void Tarjan(int u, int fa)
{
    dfn[u] = low[u] = ++dep;
    Stack[top++] = u;
    int tol = 0;
    for(int i = head[u]; i != -1; i = edge[i].nxt)
    {
        int v = edge[i].v;
        if(!dfn[v])
        {
            sum++;
            Tarjan(v, u);
            low[u] = min(low[u], low[v]);
        }
        else if(fa == v)
        {
            if(tol)
                low[u] = min(low[u], dfn[v]);
            tol++;
        }
        else
            low[u] = min(low[u], dfn[v]);
    }
    if(dfn[u] == low[u])
    {
        int x;
        scc++;
        do
        {
            x = Stack[--top];
            belong[x] = scc;
        }while(x != u);
    }
}
int main()
{
    while(scanf("%d%d", &n, &m) != EOF && (n || m))
    {
        scc = top = dep = cnt = 0;
        memset(dfn, 0, sizeof(dfn));
        memset(low, 0, sizeof(low));
        memset(head, -1, sizeof(head));
        while(m--)
        {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            addedge(u, v, w);
        }
        sum = 1;
        Tarjan(1, 1);
        int ans = 10010;
        if(sum < n)
            puts("0");
        else
        {
            for(int i = 1; i <= n; i++)
                for(int j = head[i]; j != -1; j = edge[j].nxt)
                {
                    int v = edge[j].v;
                    if(belong[i] != belong[v])
                        ans = min(ans, edge[j].w);
                }
            if(ans == 10010)
                puts("-1");
            else if(ans == 0)
                puts("1");
            else
                printf("%d\n", ans);
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值