zoukankan      html  css  js  c++  java
  • 最小生成树之Kruskal

    模板题,学习一下最小生成树的Kruskal算法

    对于一个连通网(连通带权图,假定每条边上的权均为大于零的实数)来说,每棵树的权(即树中所有边的权值总和)也可能不同

    具有权最小的生成树称为最小生成树

    生成树:

    • 无向连通图的边的集合
    • 无回路
    • 连接所有的点

    最小:

    • 所有边的权值之和最小

    n个顶点的树有n-1条边

    时间复杂度:O(ElogE)

    对于稀疏图来说

    按所给的边的权值从小到大排序,如果该边不与已经选的边形成环就选择它

    这里用并查集来实现

    第i条边的端点放在u、v数组中,权值保存在w中

    这里用的是间接排序,也就是排的是每条边的序号,放在rank数组中

    下面是两道模板题:

    HDU 1863 畅通工程

     1 //#define LOCAL
     2 #include <algorithm>
     3 #include <cstdio>
     4 #include <cstring>
     5 using namespace std;
     6 
     7 const int maxn = 5000;
     8 int u[maxn], v[maxn], w[maxn], parent[maxn], rank[maxn];
     9 int m, n;
    10 
    11 bool cmp(const int i, const int j)
    12 {
    13     return (w[i] < w[j]);
    14 }
    15 
    16 int GetParent(int a)
    17 {
    18     return parent[a] == a ? a : parent[a] = GetParent(parent[a]);
    19 }
    20 
    21 int kruskal(void)
    22 {
    23     int cnt = 0, weight = 0;
    24     for(int i = 0; i < m; ++i)
    25     {
    26         int edge = rank[i];
    27         int x = GetParent(u[edge]);
    28         int y = GetParent(v[edge]);
    29         if(x != y)
    30         {
    31             weight += w[edge];
    32             ++cnt;
    33             parent[x] = y;
    34         }
    35     }
    36     if(cnt < n - 1)    weight = 0;
    37     return weight;
    38 }
    39 
    40 int main(void)
    41 {
    42     #ifdef LOCAL
    43         freopen("1863in.txt", "r", stdin);
    44     #endif
    45 
    46 
    47     while(scanf("%d%d", &m, &n) == 2 && m)
    48     {
    49         for(int i = 0; i < m; ++i)
    50             scanf("%d%d%d", &u[i], &v[i], &w[i]);
    51         for(int i = 0; i < n; ++i)    parent[i] = i;
    52         for(int i = 0; i < m; ++i)    rank[i] = i;
    53         sort(rank, rank + m, cmp);
    54         int ans = kruskal();
    55         if(ans)
    56             printf("%d
    ", ans);
    57         else
    58             printf("?
    ");
    59     }
    60     return 0;
    61 }
    代码君一

    POJ 1861 Network

    感觉这道题略坑啊,它并没有说是多组输入啊,而且输出的第一个数是边里面的最大权值啊,数组开了1000多开小了啊,还有各种小错误啊。Orz

    好吧,这些都是我的错误,上来就套模板,没有好好读题

     1 //#define LOCAL
     2 #include <iostream>
     3 #include <cstdio>
     4 #include <cstring>
     5 #include <algorithm>
     6 using namespace std;
     7 
     8 const int maxn = 1000 + 10;
     9 int v[maxn], u[maxn], r[maxn], p[maxn], w[maxn], path[maxn];
    10 int n, m, cnt, ans;
    11 
    12 int Find(int a)
    13 {
    14     return p[a] == a ? a : p[a] = Find(p[a]);
    15 }
    16 
    17 bool cmp(const int i, const int j)
    18 {
    19     return (w[i] < w[j]);
    20 }
    21 
    22 void Kruskal(void)
    23 {
    24     cnt = 0, ans = -1;
    25     for(int i = 0; i < m; ++i)
    26     {
    27         int edge = r[i];
    28         int x = Find(u[edge]);
    29         int y = Find(v[edge]);
    30         if(x != y)
    31         {
    32             ans = max(ans, w[edge]);
    33             p[x] = y;
    34             path[cnt++] = i;
    35         }
    36     }
    37 }
    38 
    39 void OutPut(void)
    40 {
    41     printf("%d
    %d
    ", ans, cnt);
    42     for(int i = 0; i < cnt; ++i)
    43         printf("%d %d
    ", u[r[path[i]]], v[r[path[i]]]);
    44 }
    45 
    46 int main(void)
    47 {
    48     #ifdef LOCAL
    49         freopen("1861in.txt", "r", stdin);
    50     #endif
    51 
    52     while(scanf("%d%d", &n, &m) == 2)
    53     {
    54         for(int i = 0; i < m; ++i)
    55         scanf("%d%d%d", &u[i], &v[i], &w[i]);
    56         for(int i = 0; i < n; ++i)    p[i] = i;
    57         for(int i = 0; i < m; ++i)    r[i] = i;
    58         sort(r, r + m, cmp);
    59         Kruskal();
    60         OutPut(); 
    61     }
    62     
    63     return 0;
    64 }
    代码君二

    POJ 2560 Freckles

    题意:给出n个点的坐标,求最小生成树的长度。奇怪的是G++没过,C++却过了

     1 //#define LOCAL
     2 #include <iostream>
     3 #include <cstdio>
     4 #include <cstring>
     5 #include <algorithm>
     6 #include <cmath>
     7 using namespace std;
     8 
     9 const int maxn = 5000 + 10;
    10 struct Node
    11 {
    12     double x, y;
    13 }pos[maxn];
    14 
    15 int u[maxn], v[maxn], r[maxn], p[maxn];
    16 double w[maxn];
    17 
    18 bool cmp(const int i, const int j)
    19 {
    20     return (w[i] < w[j]);
    21 }
    22 
    23 int Find(int a)
    24 {
    25     return p[a] == a ? a : p[a] = Find(p[a]);
    26 }
    27 
    28 double Kruskal(int cnt)
    29 {
    30     double ans = 0.0;
    31     for(int i = 0; i < cnt; ++i)
    32     {
    33         int edge = r[i];
    34         int x = Find(u[edge]);
    35         int y = Find(v[edge]);
    36         if(x != y)
    37         {
    38             ans += w[edge];
    39             p[x] = y;
    40         }
    41     }
    42     return ans;
    43 }
    44 
    45 int main(void)
    46 {
    47     #ifdef LOCAL
    48         freopen("2560in.txt", "r", stdin);
    49     #endif
    50 
    51     int n, cnt;
    52     while(scanf("%d", &n) == 1)
    53     {
    54         for(int i = 0; i < n; ++i)    p[i] = i;
    55         for(int i = 0; i < n; ++i)
    56             scanf("%lf %lf", &pos[i].x, &pos[i].y);
    57         cnt = 0;
    58         for(int i = 1; i < n; ++i)
    59             for(int j = 0; j < i; ++j)
    60             {
    61                 u[cnt] = i;
    62                 v[cnt] = j;
    63                 r[cnt] = cnt;
    64                 w[cnt++] = sqrt((pos[i].x-pos[j].x)*(pos[i].x-pos[j].x) + (pos[i].y-pos[j].y)*(pos[i].y-pos[j].y));
    65             }
    66         sort(r, r + cnt, cmp);
    67         printf("%.2lf
    ", Kruskal(cnt));
    68     }
    69     
    70     return 0;
    71 }
    代码君三
  • 相关阅读:
    naturalWidth、naturalHeight来获取图片的真实宽高
    网站访问量等数据统计
    电话号码中间四位用****代替
    前端通过url页面传值
    前端存取cookie
    SQL Server 硬件和软件要求
    sql server 2017安装
    Js小知识及一些常见易混淆的知识点
    前端学习资料汇总
    短信验证码
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/3958599.html
Copyright © 2011-2022 走看看