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;
}