#HDU 4738 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

题目大意 : 两军在海上打仗, 一方希望对面小岛不要全部都有桥连着,否则太被动了!所以希望拆掉一座桥 。但是对面也不傻,每座桥都有数量不等的警卫把守着,假设你的士兵的战斗能力和对面战斗能力一样, 求出最少需要消耗多少兵力。

简单地说,求出权值最小的割边。

思路 : 图论里的坑点基本给他占了大半,罗列下有哪些。首先,这个岛群是可以不连通的,这样正和他意啊,他想让岛群不连通,现在已经不连通了,所以派出的士兵数为0.   其次:如果有一座桥没有士兵看守, 是不是不用派士兵去了呢?当然不是!如果没有人看守,你还是得派人去炸桥,因为桥还在那呢 (被这个坑哭了T_T),所以派一个人去就OK了。最后,如果有重边,就会出现这种情况:

这张图的数据是 : 2  2 , 1  2  2, 1  2  0   这个答案应该是多少呢?不是1! 更不是2!因为有重边的话他就已经不是一个桥了,你删掉一条边它还是可以连通两边,所以我们在判断是否为割边(桥)的时候就得多加一个条件了,解决这些细节,相信你就可以A掉啦QAQ

AC代码 :

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 1e6 + 5;
const int maxm = 1e3 + 5;
const int INF = 0x3f3f3f3f;

struct node
{
    int v, w, next;  //链式前向星存图
}e[maxn];
int dfn[maxm], low[maxm], head[maxm], p[maxm];  
int n, m, cnt, oth, tot, flag, min_;
int vis[maxm][maxm];  //vis标记重边
int find_(int x) {
    while (x != p[x]) x = p[x] = p[p[x]];  //并查集的查
    return x;
}
void unite(int x, int y) {   //并查集的并
    x = find_(x);
    y = find_(y); 
    if (x != y) p[x] = y;
}
void init() {  //别忘了初始化
    memset(e, 0, sizeof(e));
    memset(dfn, 0, sizeof(dfn));
    memset(low, 0, sizeof(low));
    memset(head, -1, sizeof(head));
    memset(vis, 0, sizeof(vis));
    for (int i = 1; i <= n; i++) p[i] = i;
    cnt = oth = tot = flag = 0;
    min_ = INF;
}
void add (int from, int to, int dis) {
    e[++cnt].v = to;
    e[cnt].next = head[from];
    e[cnt].w = dis;
    head[from] = cnt;
}
void tarjan(int x, int fa) {
    dfn[x] = low[x] = ++tot;
    for (int i = head[x]; i != -1; i = e[i].next) {
        int v = e[i].v;
        if (!dfn[v]) {
            tarjan(v, x);
            low[x] = min (low[x], low[v]);  //加一个条件,这条边只出现了一次
            if (low[v] > dfn[x] && vis[x][v] < 2 && vis[v][x] < 2)flag = 1, min_ = min (min_, e[i].w);
        }
        else if (v != fa) low[x] = min (low[x], dfn[v]);
    }
}

int main()
{
    while (scanf("%d%d", &n, &m) && n + m) {
        init();
        for (int i = 0; i < m; i++) {
            int ui, vi, wi;
            scanf("%d%d%d", &ui, &vi, &wi);
            add (ui, vi, wi);
            add (vi, ui, wi);
            unite(ui, vi);
            vis[ui][vi]++;
            vis[vi][ui]++;
        }
        int sum = 0;
        for (int i = 1; i <= n; i++) {
            if (find_(i) == i) sum++;
        }
        if (sum > 1) {cout << 0 << endl; continue;}
        for (int i = 1; i <= n; i++) {
            if (!dfn[i]) tarjan(i, i);
        }
        if (flag) {
            if (!min_) cout << 1 << endl;
            else cout << min_ << endl;
        }
        else cout << -1 << endl;
    }
    return 0;
}

 

 

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值