题目链接:http://code.hdu.edu.cn/showproblem.php?pid=1233
并查集的运用, 实质就是求最小生成树。先对所有的村庄距离从小到大排序,然后判断村庄之间是否属于同一集合,不是则将距离相加。属于同一集合,说明村庄连成了环,就不符合树的定义了。这样扫描下来,就求得最小生成树了。
要特别注意的是,数组越界问题。这个得益于Dwylkz的指点。由于村庄最多假设为100,为了防止边数越界,数组应该开到100 * 100 (10000)左右。
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 5 const int maxn = 10000 + 10; // 100个村庄边数最多为10000 6 struct sets 7 { 8 int v1, v2; // v1,v2分别表示村庄1和村庄2 9 int value; // 保存两村庄间的距离 10 } test[maxn]; 11 12 int set[maxn]; // 保存集合中的代表 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 == set[x] ? x : find(set[x]); 22 } 23 24 int main() 25 { 26 int a, b, i, n, cnt; 27 while (scanf("%d", &n) != EOF && n) 28 { 29 for (i = 1; i <= n; i++) 30 { 31 set[i] = i; // 初始化为n个不相交的集合 32 } 33 int len = n * (n-1) / 2; // 输入的行数 34 for (i = 0; i < len; i++) 35 { 36 scanf("%d%d%d", &test[i].v1, &test[i].v2, &test[i].value); 37 } 38 sort(test, test+len, cmp); // 对距离从小到大排序 39 for (cnt = i = 0; i < len; i++) 40 { 41 a = find(test[i].v1); 42 b = find(test[i].v2); 43 if (a != b) // 不属于同一集合,则将距离相加,这个已保证能得到最小生成树 44 { 45 set[a] = b; 46 cnt += test[i].value; 47 } 48 } 49 printf("%d\n", cnt); 50 } 51 return 0; 52 }