Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3898 Accepted Submission(s): 1225
题意:有n座岛和m条桥,每条桥上有w个兵守着,现在要派不少于守桥的士兵数的人去炸桥,只能炸一条桥,使得这n座岛不连通,求最少要派多少人去。
分析:只需要用Tarjan算法求出图中权值最小的那条桥就行了。但是这题有神坑。
第一坑:如果图不连通,不用派人去炸桥,直接输出0
第二坑:可能会有重边,即两座岛之间有多座桥(坑T_T)
第三坑:如果桥上没有士兵守着,那至少要派一个人去炸桥。
1 //2016.9.16 2 #include <iostream> 3 #include <cstdio> 4 #include <algorithm> 5 #include <cstring> 6 #define N 1005 7 8 using namespace std; 9 10 const int inf = 0x3f3f3f3f; 11 int edge[N][N], vis[N], num[N], low[N], n, m, Index, ans, root;//vis表示连通的集合。 12 13 void tarjan(int cur, int fa) 14 { 15 Index++; 16 num[cur] = low[cur] = Index; 17 vis[cur] = 1; 18 for(int i = 1; i <= n; i++) 19 { 20 if(edge[cur][i]!=inf) 21 { 22 if(num[i] == 0) 23 { 24 tarjan(i, cur); 25 low[cur] = min(low[cur], low[i]); 26 if(low[i]>num[cur]) 27 if(ans>edge[cur][i]) 28 ans = edge[cur][i]; 29 }else if(i != fa) 30 { 31 low[cur] = min(low[cur], num[i]); 32 } 33 } 34 } 35 return; 36 } 37 38 int main() 39 { 40 int u, v, w; 41 while(scanf("%d%d", &n, &m)!=EOF) 42 { 43 if(!n && !m)break; 44 memset(edge, inf, sizeof(edge));//图权值为inf表示断开 45 memset(num, 0, sizeof(num)); 46 memset(low, 0, sizeof(low)); 47 memset(vis, 0, sizeof(vis)); 48 Index = 0, root = 1, ans = inf; 49 for(int i = 0; i < m; i++) 50 { 51 scanf("%d%d%d", &u, &v, &w); 52 if(edge[u][v] == inf) 53 { 54 edge[u][v] = w; 55 edge[v][u] = w; 56 }else//如果重边,必不为割边,但也不为断开,把权值设为inf一半 57 { 58 edge[u][v] = inf/2; 59 edge[v][u] = inf/2; 60 } 61 } 62 tarjan(1, root); 63 bool fg = true;//判断图是否连通 64 for(int i = 1; i <= n; i++) 65 if(!vis[i]) 66 { 67 printf("0\n"); 68 fg = false; 69 break; 70 } 71 if(!fg)continue; 72 if(ans == inf || ans == inf/2)printf("-1\n"); 73 else if(ans == 0)printf("1\n");//若无守兵,至少派一人去 74 else printf("%d\n", ans); 75 } 76 77 return 0; 78 }
原文:http://www.cnblogs.com/Penn000/p/5877353.html