poj 2421 Constructing Roads 解题报告

题目链接: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。感觉这样会少讨论很多情况,希望以这种方法过了的读者可以指点一下,好像在上面的代码修改比较难实现。

 

posted @ 2013-09-11 07:48  windysai  阅读(282)  评论(0编辑  收藏  举报