HDU 4738 Caocao's Bridges(双连通分量求桥)

题目链接

题目大意

  给一个(或多个)无向图,问是否有办法去掉一条边,使得至少有两个以上的无向图,如果可以问最少花费。

解题思路

  很明显就是找权值最小的桥,但是如果本来就有多个无向图的话,那就没有必要炸桥了。另外还有一个坑点是,如果得到的桥的最小w为0,那么最至少得派一个人去炸(没人怎么炸桥。。。)。计算边双联通分量的时候,要记得同一条边只能用一次,否则的话,子节点永远可以指向父亲节点就不存在桥了。

代码

const int maxn = 1e3+10;
const int maxm = 1e6+10;
int h[maxn], cg;
struct E {
    int to, nex, w;
} e[maxm<<1];
void ad(int u, int v, int w) {
    e[cg].to = v;
    e[cg].w = w;
    e[cg].nex = h[u];
    h[u] = cg++;
}
int dfn[maxn], low[maxn], dn, minn;
void tarjan(int u, int fa) {
    dfn[u] = low[u] = ++dn;
    for (int i = h[u]; ~i; i = e[i].nex) {
        if (i==(fa^1)) continue;
        int v = e[i].to;
        if (!dfn[v]) {
            tarjan(v, i);
            low[u] = min(low[u], low[v]);
            if (dfn[u]<low[v]) minn = min(minn, e[i].w);
        }
        else low[u] = min(low[u], dfn[v]);
    }
}
int n, m; 
int main() {
    while(~scanf("%d%d", &n, &m) && (n||m)) {
        cg = dn = 0; NIL(h); minn = INF;
        zero(dfn); zero(low);
        for (int i = 0, u, v, w; i<m; ++i) {
            scanf("%d%d%d", &u, &v, &w);
            ad(u,v,w); ad(v,u,w);
        }
        int cnt = 0;
        for (int i = 1; i<=n; ++i)
            if (!dfn[i]) {
                tarjan(i, -1); ++cnt;
            }
	if(cnt != 1) printf("0\n");
        else if (minn==INF) printf("-1\n");
	else printf("%d\n", !minn?1:minn);
    }
    return 0;
}
posted @ 2020-05-17 11:58  shuitiangong  阅读(122)  评论(0编辑  收藏  举报