You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

HDU4738 Caocao's Bridges

一、题目描述

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

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

现在问刘备最少派多少人去炸桥。 如果无法使曹操的点成为多个连通图,则输出-1.

测试输入

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

测试输出

-1
4

二、解题思路

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

Tips

  • ①. 有重边,注意重边处理,要用链式前向星。我们一直在用链式前向星,所以这个不是问题,反倒是使用邻接表的同学们需要烦恼了~

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

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

三、实现代码

#include <bits/stdc++.h>
using namespace std;
const int N = 500010, M = N << 1;
const int INF = 0x3f3f3f3f;

int n, m;
int res;

// 链式前向星
int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c = 0) {
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}

// Tarjan求割边
int dfn[N], low[N], ts;
void tarjan(int u, int fa) {
    dfn[u] = low[u] = ++ts;
    for (int i = h[u]; ~i; i = ne[i]) {
        int v = e[i];
        if (v == fa) continue;
        if (!dfn[v]) {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            if (low[v] > dfn[u]) res = min(res, w[i]);
        } else
            low[u] = min(low[u], dfn[v]);
    }
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("HDU4738.in", "r", stdin);
#endif
    while (~scanf("%d%d", &n, &m) && n) {
        ts = idx = 0;
        memset(h, -1, sizeof h);
        memset(dfn, 0, sizeof dfn);
        memset(low, 0, sizeof low);
        res = INF;

        while (m--) {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            add(a, b, c), add(b, a, c);
        }

        int dcc_cnt = 0;
        for (int i = 1; i <= n; i++)
            if (!dfn[i]) tarjan(i, -1), dcc_cnt++;

        if (dcc_cnt > 1) { // tarjan多次说明不连通直接输出0
            printf("0\n");
            continue;
        }
        if (res == INF)
            res = -1;
        else if (res == 0)
            res = 1;
        printf("%d\n", res);
    }
    return 0;
}