题目链接:http://poj.org/problem?id=2421
实际上又是考最小生成树的内容,也是用到kruskal算法。但稍稍有点不同的是,给出一些已连接的边,要在这些边存在的情况下,拓展出最小生成树来。
一般来说,过到这四组数据大体上就能AC了。 1、题目给出的案例数据 2、连接的道路可能把所有的村庄都已经连通了 3、两个村庄给出多次,即连接这两个村庄的道路是重复的!。
2、3这两种情况的数据如下(为了好看,自己出了一组,当然Sample Input 那组也行):
情况2(所有村庄已连通): 情况3:
还有第4种情况:
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 5 const int maxe = 10000 + 10; // 这里开小点也行,因为只存储矩阵不够一半的数据 6 int rep[maxe], vis[maxe]; 7 8 struct sets 9 { 10 int v1, v2; 11 int value; 12 } exa[maxe]; 13 14 int cmp(sets a, sets b) 15 { 16 return a.value < b.value; 17 } 18 19 int find(int x) 20 { 21 return x == rep[x] ? x : find(rep[x]); 22 } 23 24 int main() 25 { 26 int i, j, n, a, b, x, y, t, cnt, flag; 27 while (scanf("%d", &n) != EOF) 28 { 29 for (i = 1; i <= n; i++) 30 { 31 rep[i] = i; 32 } 33 cnt = 0; 34 for (i = 1; i <= n; i++) 35 { 36 for (j = 1; j <= n; j++) 37 { 38 scanf("%d", &a); 39 if (i < j) // 只存储上三角矩阵 40 { 41 exa[cnt].v1 = i; 42 exa[cnt].v2 = j; 43 exa[cnt].value = a; 44 cnt++; 45 } 46 } 47 } 48 sort(exa, exa+cnt, cmp); // 对长度进行从小到大排序 49 flag = 0; 50 memset(vis, 0, sizeof(vis)); 51 scanf("%d", &t); 52 while (t--) 53 { 54 scanf("%d%d", &a, &b); 55 if (a > b) 56 swap(a, b); // 刚开始就保持小的元素的祖先是大的元素 57 x = find(a); 58 y = find(b); 59 if (x > y) 60 { 61 swap(x, y); // 合并集合的时候,有可能使得大的元素的祖先变成了是比它小的元素 62 } 63 if (vis[a] && vis[b]) // 两个村庄在之前已经被访问过,这是为了处理情况4的情况的 64 rep[x] = y; 65 else 66 { 67 if (x == y) // 所有村庄都有路可通 68 flag = 1; 69 if (!vis[a] && !vis[b]) 70 { 71 rep[x] = y; 72 vis[a] = vis[b] = 1; 73 } 74 else if (!vis[a]) 75 { 76 rep[x] = y; 77 vis[a] = 1; 78 } 79 else if (!vis[b]) 80 { 81 rep[x] = y; 82 vis[b] = 1; 83 } 84 } 85 } 86 if (!flag) 87 { 88 int minval = 0; 89 for (i = 0; i < cnt; i++) 90 { 91 x = find(exa[i].v1); 92 y = find(exa[i].v2); 93 if (x != y) 94 { 95 minval += exa[i].value; 96 if (x < y) // 为了与前面相一致,也是小的元素的祖先是大的元素
97 rep[x] = y; 98 else 99 rep[y] = x; 100 } 101 } 102 printf("%d\n", minval); 103 } 104 else 105 printf("0\n"); 106 } 107 return 0; 108 }
其实,还有一种比较简单的方法,但是目前还不会实现。Dwylkz给的解法:题目给的已连通的村庄的value都设为0。感觉这样会少讨论很多情况,希望以这种方法过了的读者可以指点一下,好像在上面的代码修改比较难实现。