HDU 4738-Caocao's Bridges-无向图找桥 DAG Tarjan

Caocao’s Bridges

Problem Description
Caocao was defeated by Zhuge Liang and Zhou Yu in the battle of Chibi. But he wouldn’t give up. Caocao’s army still was not good at water battles, so he came up with another idea. He built many islands in the Changjiang river, and based on those islands, Caocao’s army could easily attack Zhou Yu’s troop. Caocao also built bridges connecting islands. If all islands were connected by bridges, Caocao’s army could be deployed very conveniently among those islands. Zhou Yu couldn’t stand with that, so he wanted to destroy some Caocao’s bridges so one or more islands would be seperated from other islands. But Zhou Yu had only one bomb which was left by Zhuge Liang, so he could only destroy one bridge. Zhou Yu must send someone carrying the bomb to destroy the bridge. There might be guards on bridges. The soldier number of the bombing team couldn’t be less than the guard number of a bridge, or the mission would fail. Please figure out as least how many soldiers Zhou Yu have to sent to complete the island seperating mission.

Input
There are no more than 12 test cases.

In each test case:

The first line contains two integers, N and M, meaning that there are N islands and M bridges. All the islands are numbered from 1 to N. ( 2 <= N <= 1000, 0 < M <= N2 )

Next M lines describes M bridges. Each line contains three integers U,V and W, meaning that there is a bridge connecting island U and island V, and there are W guards on that bridge. ( U ≠ V and 0 <= W <= 10,000 )

The input ends with N = 0 and M = 0.

Output
For each test case, print the minimum soldier number Zhou Yu had to send to complete the mission. If Zhou Yu couldn’t succeed any way, print -1 instead.

Sample Input

3 3
1 2 7
2 3 4
3 1 4
3 2
1 2 7
2 3 4
0 0

Sample Output

-1
4

Source
2013 ACM/ICPC Asia Regional Hangzhou Online

题解参考链接 http://www.cnblogs.com/Griselda/archive/2013/11/20/3433381.html
题目:
  曹操在长江上建立了一些点,点之间有一些边连着。如果这些点构成的无向图变成了连通图,那么曹操就无敌了。刘备为了防止曹操变得无敌,就打算去摧毁连接曹操的点的桥。但是诸葛亮把所有炸弹都带走了,只留下一枚给刘备。所以刘备只能炸一条桥。
  题目给出n,m。表示有n个点,m条桥。
  接下来的m行每行给出a,b,c,表示a点和b点之间有一条桥,而且曹操派了c个人去守卫这条桥。
  现在问刘备最少派多少人去炸桥。
  如果无法使曹操的点成为多个连通图,则输出-1.
思路:
  就是用tarjan算法算出桥的数量,再比较哪一个的值最小。
Tips:
  注意三点:
  ①. 有重边,所以tarjan算法要处理重边。有两种处理方法,一种是先把所有的边存下,发现两点有重边的时候就只给这两个点连一条权值为无穷大的边。或者是在tarjan算法里处理重边,即使之求u或u的子树能够追溯到的最早的栈中节点的次序号时可访问父节点的次序号。
  ②. 如果无向图图本身已经有两个连通图了,就无需派人去炸桥,这时候输出0。
  ③. 如果求出来的最小权值桥的守卫人数为0时,也需要派出一个人去炸桥。

//无向图找桥 DAG Tarjan
#include<iostream>
#include<algorithm>  
#include<string.h>
using namespace std;

#define MAX_N 1010
#define MAX_M  MAX_N*MAX_N*2//类似有向边
#define INF 0xfffffff

int n, m;
//dfn为第一次访问的时间,low为该结点的子孙结点能连接到最小的结点的时间点(dfn点)
//head为当前点最靠近的一条边(相当于链表)
int dfn[MAX_N], low[MAX_N], head[MAX_N];

//ans是所求结果,tot为边的编号,num为访问时候的时间点
int ans = INF, tot, num;

struct Bridge {
    //v 下一个点 ;c 边的权值;id 增加边时候的顺序编号;next 下一条边的编号
    int v, c, id, next;
}e[MAX_M];


//双向增加边
void addBridge(int u, int v, int c, int id) 
{
    e[tot].v = v;
    e[tot].c = c;
    e[tot].id = id;
    e[tot].next = head[u];//这两句,把边当作链表就行了。
    head[u] = tot++;//访问时候,能够访问到全部边
}
void tarjan(int u, int fa) {
    dfn[u] = low[u] = ++num;
    for (int i = head[u]; ~i; i = e[i].next) {//遍历这条边的所有相连的边
        int v = e[i].v;
        int id = e[i].id;
        if (fa == id) continue;//同一条边
        if (!dfn[v]) {//如果没有访问过
            tarjan(v, id);
            low[u] = min(low[u], low[v]);
            if (dfn[u] < low[v]) {//说明此处为桥,更新ans
                ans = min(ans, e[i].c);
            }
        }
        else {
            //在任何深度优先搜索中,
            //同一强连通分量内的所有顶点均在同一棵深度优先搜索树中
            //所以此处不是low[v](基于有向图的)
            low[u] = min(low[u], dfn[v]);
        }
    }
}
int main() {
    int u, v, w;
    while (cin >> n >> m ,n||m) {
        tot = 0;
        memset(head, -1, sizeof(head));
        for (int i = 1; i <= m; i++) {
            cin >> u >> v >> w;
            addBridge(u, v, w, i);
            addBridge(v, u, w, i);
        }

        ans = INF;
        num = 0;
        memset(dfn, 0, sizeof(dfn));
        int ok = 0;
        for (int i = 1; i <= n; i++)
        {
            if (!dfn[i]) {//判断是否是多个连通图
                ok++;
                tarjan(i, 0);
            }
        }
        if (ans == 0)ans = 1;
        if (ans == INF)ans = -1;//多个连通图,即原图不连通
        if (ok > 1)ans = 0;
        cout << ans << endl;
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值