hdu4738 Caocao's Bridges
http://acm.hdu.edu.cn/showproblem.php?pid=4738
题目大意:曹操赤壁之战大败,于是卷土重来。为了避免水上作战,他在长江上建立了一些岛屿,这样他的士兵就可以在岛屿上攻击到
周瑜的军队。同时,为了更方便各个岛屿的支援与部署,他在一些岛屿之间又修建了一些桥,并且在桥上准备了一些守卫的士兵。周瑜
看到后当然要破坏这些岛屿的连接,然而诸葛亮只给他留下了一个bomb,他如果想要炸毁一座桥需要派出至少和守卫士兵数相等的敢死队
去。问最少需要派出多少人。
很佩服出题人有这么大的脑洞。
很直白的连通图找桥,然后取这些桥中权值(守卫士兵数)最小的即可。可是我太天真了。
WA了9次。呵呵呵呵呵
坑点:
1:可能一开始给出的图根本不是连通图(这也可以),这样岛屿没连接,不用人去, 输出人数是0;
2:输入中含有重复边,就是两个岛屿之间有两座桥。这样明显这两点间的边即使是桥也不算了,耿直的
用数组的直接将权值归为oo即可。或者用邻接表写的标记重边。
3:某桥上的守卫士兵数是0.(一开始把图的权值初始化成0了结果这条边被判成不存在了。。。WA了三次后才发现,初始化为-1才判进去。)
按题面的叙述是0,然而正确的是1。因为bomb至少需要一个人带过去...
附AC代码:
#include <stdio.h> #include <algorithm> #include <string.h> using namespace std; #define oo 0x3f3f3f3f int G[1005][1005], ans, fa[1005], dfn[1005], low[1005], Time, m, n, nblocks; void Tarjin(int u, int father) { dfn[u] = low[u] = ++Time; fa[u] = father; for(int i=1; i<=n; i++) { if(G[u][i]!=-1) { if(!dfn[i]) { Tarjin(i, u); low[u] = min(low[u], low[i]); if(low[i]>dfn[u])ans = min(ans, G[u][i]); } else if(i!=father) low[u] = min(low[u], dfn[i]); } } } int main() { while(scanf("%d %d", &n, &m), m+n) { int a, b, c; memset(low, 0, sizeof(low)); memset(dfn, 0, sizeof(dfn)); memset(G, -1, sizeof(G)); for(int i=1; i<=m; i++) { scanf("%d %d %d", &a, &b, &c); if(G[a][b]==-1) G[a][b] = G[b][a] = c; else G[a][b] = G[b][a] = oo; } nblocks = 0; Time = 0; ans = oo; Tarjin(1, -1); int flag = 1; for(int i=1; i<=n; i++) if(!dfn[i]) { flag = 0; break; } if(!flag) { printf("0\n"); continue; } if(ans==oo)printf("-1\n"); else printf("%d\n", ans==0?1:ans); } return 0; }