zoukankan      html  css  js  c++  java
  • ACM/ICPC 之 Kruskal范例(ZOJ1203-POJ1861(ZOJ1542))

      两道最小生成树范例,Kruskal解法-以边为主体扩展最小生成树,需要利用并查集


    ZOJ1203-Swordfish

      

      题意:求n个给定平面坐标的城市中的一条平面距离上的最短路长(保留两位小数)

      题解:这道题数据不是很大,用Kruskal和Prim等算法都能够做。

         Kruskal的算法思路是以边为主体扩展结点,即先选取权值最少的边,将两个不连通的端点加入到同一集合中(使其连通),舍去该边,接着找权值次小的,以此类推...

         如果两个端点连通,则直接舍去该边。

         因此可以先将所有边依据权值大小排序后,然后依次查找即可,为了较快地表示两个端点连通(属于同一集合),需要用到并查集的路径压缩。

     1 //剑鱼行动-Kruskal
     2 //找出n个给定平面坐标的城市中的一条最短路长(保留两位小数)
     3 //Time:0Ms    Memory:432K
     4 #include<iostream>
     5 #include<cstring>
     6 #include<cstdio>
     7 #include<cmath>
     8 #include<algorithm>
     9 using namespace std;
    10 
    11 #define MAX    101
    12 #define POW2(x) ((x)*(x))
    13 
    14 struct City {
    15     double x, y;
    16 }c[MAX];
    17 
    18 struct Edge {
    19     int u, v;    //端点
    20     double road;
    21     friend bool operator < (Edge e1, Edge e2) { return e1.road < e2.road; }
    22 }e[MAX*MAX];
    23 
    24 int n, m;
    25 int fa[MAX];
    26 double minroad;
    27 
    28 int Find(int x)
    29 {
    30     return fa[x] < 0? x : fa[x] = Find(fa[x]);    //查根+路径压缩
    31 }
    32 
    33 //加权法则合并
    34 void Union(int r1,int r2)
    35 {
    36     int num = fa[r1] + fa[r2];    //集合元素总数-以负数计数
    37     if (fa[r1] > fa[r2])    //r2集合元素多
    38     {
    39         fa[r1] = r2;
    40         fa[r2] = num;
    41     }
    42     else {    //r1集合元素多
    43         fa[r2] = r1;
    44         fa[r1] = num;
    45     }
    46 }
    47 
    48 void kruskal()
    49 {
    50     minroad = 0;
    51     memset(fa, -1, sizeof(fa));
    52     int num = 0;    //已用结点数
    53     for (int i = 0; i < m; i++)
    54     {
    55         int r1 = Find(e[i].u);
    56         int r2 = Find(e[i].v);
    57         if (r1 == r2)    continue;
    58         minroad += e[i].road;
    59         Union(r1, r2);
    60         num++;
    61         if (num == n - 1) break;
    62     }
    63 }
    64 
    65 int main()
    66 {
    67     int cas = 0;
    68     while (scanf("%d", &n), n)
    69     {
    70         for (int i = 0; i < n; i++)
    71             scanf("%lf%lf", &c[i].x, &c[i].y);
    72 
    73         m = 0;
    74         for (int i = 0; i < n; i++)
    75             for (int j = i + 1; j < n; j++)
    76             {
    77                 double d = sqrt(POW2(c[i].x - c[j].x) + POW2(c[i].y - c[j].y));
    78                 e[m].road = d;
    79                 e[m].u = i;
    80                 e[m++].v = j;
    81             }
    82 
    83         sort(e, e + m);
    84 
    85         kruskal();
    86         if (cas)    printf("
    ");    //博主在此PE过= =
    87         printf("Case #%d:
    ", ++cas);
    88         printf("The minimal distance is: %.2lf
    ", minroad);
    89     }
    90 
    91 
    92     return 0;
    93 }

    POJ1861(ZOJ1542)-Network

      题意:找出可连通网络中最长的网线长度在所有方案中最小的方案,依次输出使用的最长边长边数各边端点信息Special Judge

      题解:Sample貌似有可能是是在提醒Special Judge,也有可能是出错了,但是这个Sample确实有点...误导人...

         读英文需要注意理解题意   //the maximum length of a single cable is minimal. 

         其实就是在求一个最小生成树,思路参照上题,注意记录使用过的边。

     1 //Kruskal-除了样例和英文有点坑
     2 //Time:79Ms    Memory:348K
     3 #include<iostream>
     4 #include<cstring>
     5 #include<cstdio>
     6 #include<algorithm>
     7 using namespace std;
     8 
     9 #define MAXN 1005
    10 #define MAXM 15005
    11 
    12 struct Edge {
    13     int u, v;
    14     int d;
    15     friend bool operator < (Edge e1, Edge e2) { return e1.d < e2.d; }
    16 }e[MAXM];
    17 
    18 int n, m;
    19 int fa[MAXN];
    20 int used[MAXN];        //记录使用过的边
    21 
    22 //路径压缩+查父
    23 int Find(int x)
    24 {
    25     return fa[x] < 0 ? x : fa[x] = Find(fa[x]);
    26 }
    27 
    28 //加权合并
    29 void Union(int r1,int r2)
    30 {
    31     int num = fa[r1] + fa[r2];
    32     if (fa[r1] < fa[r2])
    33     {
    34         fa[r2] = r1;
    35         fa[r1] = num;
    36     }
    37     else {
    38         fa[r1] = r2;
    39         fa[r2] = num;
    40     }
    41 }
    42 
    43 void kruskal()
    44 {
    45     memset(fa, -1, sizeof(fa));
    46     int sum = 0;
    47     int i = 0;
    48     for (; i < m; i++)
    49     {
    50         int r1 = Find(e[i].u);
    51         int r2 = Find(e[i].v);
    52         if (r1 == r2)    continue;
    53         Union(r1, r2);
    54         used[sum++] = i;
    55         if (sum == n - 1) break;
    56     }
    57     printf("%d
    ", e[i].d);
    58     printf("%d
    ", sum);
    59     for (int j = 0; j < sum; j++)
    60         printf("%d %d
    ", e[used[j]].u, e[used[j]].v);
    61 }
    62 
    63 int main()
    64 {
    65     scanf("%d%d", &n, &m);
    66     for (int i = 0; i < m; i++)
    67         scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].d);
    68     sort(e, e + m);
    69     kruskal();
    70 
    71     return 0;
    72 }
    他坐在湖边,望向天空,她坐在对岸,盯着湖面
  • 相关阅读:
    leetcode 【 Merge Two Sorted Lists 】 python 实现
    leetcode 【 Remove Duplicates from Sorted List II 】 python 实现
    leetcode 【 Remove Duplicates from Sorted List 】 python 实现
    leetcode 【 Remove Nth Node From End of List 】 python 实现
    leetcode 【 Linked List Swap Nodes in Pairs 】 python 实现
    i++操作非原子的验证代码
    黑马MySQL数据库学习day03 级联 多表查询 连接和子查询 表约束
    mysql 原理 ~ sql查询语句
    tidb 架构 ~Tidb学习系列(3)
    mysql 查询优化 ~ 善用profie利器
  • 原文地址:https://www.cnblogs.com/Inkblots/p/5357106.html
Copyright © 2011-2022 走看看