• poj2421 Constructing Roads ——最小生成树入门题_Kruscal算法


    题目链接:http://poj.org/problem?id=2421

    题目大意:

      给定一个矩阵,第 i 行第 j 列表示点 i 和点 j 的距离是s[i][j]。然后输入Q,下面Q行,每行两个数字a,b表示点a和点b已经有路相连。求需要至少再修多长的路,可以构成一棵生成树。输出需要在修的路的总长度。

    题目思路:

      转化为最小生成树求解。有两种思路:

      1)把已经相连的两个点的权值设置为0,这样,就可以直接求最小生成树了。因为kruscal的过程中,一定会选择到已经相连的这些点,因为它们的权值是0嘛,同时,即使把它们的权值加上,也不会影响结果。这个方法我好不容易想出来了,可是还有一个问题,就是:输入a b 后,如何定位到相应的边,并把这个边的权值设置为0?开始的时候,是暴力找,超时了,然后自己想各种方法,还求出来个公式,用a,b,N,表示出边的编号。最后还是超时了。。看网上别人恰好有人也是这么个思路,但是他是怎么定位边,并把边的权值设置为0的,没仔细看,不知道为什么人家就用这种方法过了……

      2)第二种思路,如果a b 已经相连,很简单,只要它俩的根节点不同,就把它两个合并不就可以了么,这样,kruscal的过程中,就不会再加入这些已经存在的边的权值了。剩下的就是纯的kruscal问题。这个方法很好!看的别人的想法。然后自己写了一下,RE了一次,原因是,合并a b 的时候,没有判断他们的根节点是否不同。。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <cctype>
     6 #include <stack>
     7 #include <queue>
     8 #include <map>
     9 #include <set>
    10 #include <vector>
    11 #include <cmath>
    12 #include <algorithm>
    13 #define lson l, m, rt<<1
    14 #define rson m+1, r, rt<<1|1
    15 using namespace std;
    16 typedef long long int LL;
    17 const int MAXN =  0x3f3f3f3f;
    18 const int  MIN =  -0x3f3f3f3f;
    19 const double eps = 1e-9;
    20 const int dir[8][2] = {{0,1},{1,0},{0,-1},{-1,0},{-1,1},
    21   {1,1},{1,-1},{-1,-1}};
    22 typedef struct Edge {
    23   int u, v, w;
    24   bool operator < (const Edge &o) const {
    25     return w < o.w;
    26   }
    27 }Edge;
    28 const int Mam = 5000+10, Man = 100+10;
    29 Edge edge[Mam];
    30 int parent[Man];
    31 int N, Q, a, b, S[Man][Man], sum, ecnt;
    32 void init()
    33 {
    34   for (int i = 1; i <= N; ++i) parent[i] = -1;
    35 }
    36 int Find(int x)
    37 {
    38   int s;
    39   for (s = x; parent[s] >= 0; s = parent[s]) ;
    40   while (s != x) {
    41     int tmp = parent[x]; parent[x] = s; x = tmp;
    42   } return s;
    43 }
    44 void Union(int R1, int R2)
    45 {
    46   int r1 = Find(R1), r2 = Find(R2), tmp = parent[r1] + parent[r2];
    47   if (parent[r1] > parent[r2]) {
    48     parent[r1] = r2; parent[r2] = tmp;
    49   } else {
    50     parent[r2] = r1; parent[r1] = tmp;
    51   }
    52 }
    53 void kruscal()
    54 {
    55   int i, j, u, v, w, cnt = 0;
    56   for (i = 1; i < ecnt; ++i) {
    57     u = edge[i].u; v = edge[i].v; w = edge[i].w;
    58     if (Find(u) != Find(v)) {
    59         sum += w; Union(u, v); cnt++;
    60     }
    61     if (cnt >= N - 1) break;
    62   }
    63   printf("%d\n", sum);
    64 }
    65 int main(void){
    66 #ifndef ONLINE_JUDGE
    67   freopen("poj2421.in", "r", stdin);
    68 #endif
    69   int i, j, k, a, b;
    70   while (~scanf("%d", &N)) {
    71     sum = 0; k = 1;
    72     for (i = 1; i <= N; ++i) {
    73       for (j = 1; j <= N; ++j) {
    74         scanf("%d", &S[i][j]);
    75         if (i < j) {
    76           edge[k].u = i; edge[k].v = j;
    77           edge[k].w = S[i][j]; k++;
    78         }
    79       }
    80     }
    81     ecnt = k;
    82     init();
    83     scanf("%d", &Q);
    84     for (i = 0; i < Q; ++i) {
    85       scanf("%d%d", &a, &b);
    86       if (Find(a) != Find(b)) Union(a, b); //这里要判断一下根节点是不是相同,再合并!RE一次
    87     }
    88     sort(edge, edge + ecnt);
    89     kruscal();
    90   }
    91 
    92   return 0;
    93 }

      Code::Blocks超级难用赶脚……这两天老是用着用着就假死……然后强制关闭。。很不爽。。唉,还是回来乖乖地用gvim吧,自己学着写脚本,以后就不怕了。O(∩_∩)O哈哈~

  • 相关阅读:
    接口自动化1-基础知识
    pytest-fixture之conftest.py
    测试人员一定要懂的ADB操作,赶紧来看一看~
    必看!利用装饰器,帮你自动处理异常并优雅实现重跑case
    最全Airtest接口功能介绍和示例总结,新手同学千万不能错过呀!(二)
    总结一波 Redis 面试题,收藏起来!
    IntelliJ IDEA 2020.2.4款 神级超级牛逼插件推荐
    华为 Java 开发编程军规,谁违反谁走
    CTO:再写if-else,逮着罚款1000!
    VSCode 上竟然也能约会,谈对象了???
  • 原文地址:https://www.cnblogs.com/liuxueyang/p/3054156.html
Copyright © 2020-2023  润新知