最小生成树

举报
用户已注销 发表于 2021/11/19 01:02:51 2021/11/19
【摘要】 目录 一,Kruskal 二,Kruskal实战 POJ 2349 Arctic Network 力扣 1584. 连接所有点的最小费用 三,Prim 四,Prim实战 力扣 1584. 连接所有点的最小费用 一,Kruskal 算法思路: 开始把每个点当做一棵独立的树,每次选所有不在一棵树上的...

目录

一,Kruskal

二,Kruskal实战

POJ 2349 Arctic Network

力扣 1584. 连接所有点的最小费用

三,Prim

四,Prim实战

力扣 1584. 连接所有点的最小费用


一,Kruskal

算法思路:

开始把每个点当做一棵独立的树,每次选所有不在一棵树上的两点构成的边中的最短边,把这两点连起来,两棵树合并成一棵树,

每次连一条边,直到所有的点都连成一棵树。

 

 

 

 

 

模板代码:


  
  1. const int N = 1000; //点的最大数量
  2. int en; //点的数量
  3. // TODO 用数组或者vector记录点的信息,id要从0开始
  4. int fa[N];
  5. int find(int x) //找祖先
  6. {
  7. if (fa[x] == x)return x;
  8. return fa[x] = find(fa[x]);
  9. }
  10. void merge(int i, int j)
  11. {
  12. fa[find(i)] = j;
  13. }
  14. bool inSameSet(int i, int j)
  15. {
  16. return find(i) == find(j);
  17. }
  18. struct Edge
  19. {
  20. int a;//端点id
  21. int b;//端点id
  22. int dist;
  23. };
  24. bool cmp(Edge a, Edge b)
  25. {
  26. return a.dist < b.dist;
  27. }
  28. int getLen(int i, int j) // 计算id为i和j的2个点的距离
  29. {
  30. return 0; // TODO 根据实际情况修改
  31. }
  32. vector<Edge> getEdge() // 获取所有的边
  33. {
  34. // TODO 根据实际情况修改
  35. vector<Edge> v;
  36. for (int i = 0; i < en; i++)for (int j = i + 1; j < en; j++) {
  37. Edge e = { i,j,getLen(i,j) };
  38. v.push_back(e);
  39. }
  40. return v;
  41. }
  42. //计算最小生成树,结果按照边从小到大排序
  43. vector<pair<int, int>> minCostConnectPoints()
  44. {
  45. vector<Edge> v = getEdge();
  46. sort(v.begin(), v.end(), cmp);
  47. for (int i = 0; i < en; i++)fa[i] = i;
  48. vector<pair<int, int>>ans;
  49. for (int i = 0, j = 0; j < en - 1; i++)
  50. {
  51. if (inSameSet(v[i].a, v[i].b))continue;
  52. merge(v[i].a, v[i].b);
  53. ans.push_back(make_pair(v[i].a, v[i].b));
  54. j++;
  55. }
  56. return ans;
  57. }

时间复杂度:O(ElogE),其中E是边的数量。

二,Kruskal实战

POJ 2349 Arctic Network

题目:

Description

The Department of National Defence (DND) wishes to connect several northern outposts by a wireless network. Two different communication technologies are to be used in establishing the network: every outpost will have a radio transceiver and some outposts will in addition have a satellite channel. 
Any two outposts with a satellite channel can communicate via the satellite, regardless of their location. Otherwise, two outposts can communicate by radio only if the distance between them does not exceed D, which depends of the power of the transceivers. Higher power yields higher D but costs more. Due to purchasing and maintenance considerations, the transceivers at the outposts must be identical; that is, the value of D is the same for every pair of outposts. 

Your job is to determine the minimum D required for the transceivers. There must be at least one communication path (direct or indirect) between every pair of outposts.

Input

The first line of input contains N, the number of test cases. The first line of each test case contains 1 <= S <= 100, the number of satellite channels, and S < P <= 500, the number of outposts. P lines follow, giving the (x,y) coordinates of each outpost in km (coordinates are integers between 0 and 10,000).

Output

For each case, output should consist of a single line giving the minimum D required to connect the network. Output should be specified to 2 decimal points.

Sample Input
1
2 4
0 100
0 300
0 600
150 750

Sample Output

212.13

这个题目是说,有p个站点,其中有s个可以卫星相连。(卫星不是站点)

剩下还有p-s个站点,所以还需要用p-s条直线段把这p个站点全部连接起来。

求最长的直线段至少有多长。

比如本题,我们选0,300和0,600连接卫星,

0,100用200的线段可以连上0,300,150,750用150*sqrt(2)的线段可以连上0,600

所以答案是150*sqrt(2)=212.13

所以说,这个题目的意思就是,给你p个点的坐标,所有的点都是相连的,

选1个生成树,较大的s-1条边可以用卫星代替,较小的p-s条边中,最长的那个,至少有多长?

这个题目很明显就是克鲁斯卡尔(Kruskal)算法了。

代码:


  
  1. #include<iostream>
  2. #include<vector>
  3. #include<stdio.h>
  4. #include<algorithm>
  5. #include<iomanip>
  6. #include<cmath>
  7. using namespace std;
  8. const int N = 500; //点的最大数量
  9. int en; //点的数量
  10. // 用数组或者vector记录点的信息,id要从0开始
  11. struct node
  12. {
  13. int x;
  14. int y;
  15. };
  16. node nod[N];
  17. int fa[N];
  18. int find(int x) //找祖先
  19. {
  20. if (fa[x] == x)return x;
  21. return fa[x] = find(fa[x]);
  22. }
  23. void merge(int i, int j)
  24. {
  25. fa[find(i)] = j;
  26. }
  27. bool inSameSet(int i, int j)
  28. {
  29. return find(i) == find(j);
  30. }
  31. struct Edge
  32. {
  33. int a;//端点id
  34. int b;//端点id
  35. int dist;
  36. };
  37. bool cmp(Edge a, Edge b)
  38. {
  39. return a.dist < b.dist;
  40. }
  41. int getLen(int i, int j) // 计算id为i和j的2个点的距离
  42. {
  43. return (nod[j].x - nod[i].x) * (nod[j].x - nod[i].x)
  44. + (nod[j].y - nod[i].y) * (nod[j].y - nod[i].y);
  45. }
  46. vector<Edge> getEdge() // 获取所有的边
  47. {
  48. // TODO 根据实际情况修改
  49. vector<Edge> v;
  50. for (int i = 0; i < en; i++)for (int j = i + 1; j < en; j++) {
  51. Edge e = { i,j,getLen(i,j) };
  52. v.push_back(e);
  53. }
  54. return v;
  55. }
  56. //计算最小生成树,结果按照边从小到大排序
  57. vector<pair<int, int>> minCostConnectPoints()
  58. {
  59. vector<Edge> v = getEdge();
  60. sort(v.begin(), v.end(), cmp);
  61. for (int i = 0; i < en; i++)fa[i] = i;
  62. vector<pair<int, int>>ans;
  63. for (int i = 0, j = 0; j < en - 1; i++)
  64. {
  65. if (inSameSet(v[i].a, v[i].b))continue;
  66. merge(v[i].a, v[i].b);
  67. ans.push_back(make_pair(v[i].a, v[i].b));
  68. j++;
  69. }
  70. return ans;
  71. }
  72. int main()
  73. {
  74. int t, s;
  75. cin >> t;
  76. for (int i = 0; i < t; i++)
  77. {
  78. cin >> s >> en;
  79. for (int j = 0; j < en; j++)
  80. {
  81. cin >> nod[j].x >> nod[j].y;
  82. }
  83. vector<pair<int, int>> v = minCostConnectPoints();
  84. pair<int, int> pa = v[en - s - 1];
  85. double c = 1.0;
  86. cout << fixed << setprecision(2) << sqrt(c * getLen(pa.first, pa.second)) << endl;
  87. }
  88. return 0;
  89. }

力扣 1584. 连接所有点的最小费用

给你一个points 数组,表示 2D 平面上的一些点,其中 points[i] = [xi, yi] 。

连接点 [xi, yi] 和点 [xj, yj] 的费用为它们之间的 曼哈顿距离 :|xi - xj| + |yi - yj| ,其中 |val| 表示 val 的绝对值。

请你返回将所有点连接的最小总费用。只有任意两点之间 有且仅有 一条简单路径时,才认为所有点都已连接。

示例 1:

输入:points = [[0,0],[2,2],[3,10],[5,2],[7,0]]
输出:20
解释:

我们可以按照上图所示连接所有点得到最小总费用,总费用为 20 。
注意到任意两个点之间只有唯一一条路径互相到达。
示例 2:

输入:points = [[3,12],[-2,5],[-4,1]]
输出:18
示例 3:

输入:points = [[0,0],[1,1],[1,0],[-1,1]]
输出:4
示例 4:

输入:points = [[-1000000,-1000000],[1000000,1000000]]
输出:4000000
示例 5:

输入:points = [[0,0]]
输出:0
 

提示:

1 <= points.length <= 1000
-106 <= xi, yi <= 106
所有点 (xi, yi) 两两不同。


  
  1. const int N = 1000; //点的最大数量
  2. int en; //点的数量
  3. // TODO 用数组或者vector记录点的信息,id要从0开始
  4. vector<vector<int>>p;
  5. int fa[N];
  6. int find(int x) //找祖先
  7. {
  8. if (fa[x] == x)return x;
  9. return fa[x] = find(fa[x]);
  10. }
  11. void merge(int i, int j)
  12. {
  13. fa[find(i)] = j;
  14. }
  15. bool inSameSet(int i, int j)
  16. {
  17. return find(i) == find(j);
  18. }
  19. struct Edge
  20. {
  21. int a;//端点id
  22. int b;//端点id
  23. int dist;
  24. };
  25. bool cmp(Edge a, Edge b)
  26. {
  27. return a.dist < b.dist;
  28. }
  29. int getLen(int i, int j) // 计算id为i和j的2个点的距离
  30. {
  31. return abs(p[i][0] - p[j][0]) + abs(p[i][1] - p[j][1]);
  32. }
  33. vector<Edge> getEdge() // 获取所有的边
  34. {
  35. // TODO 根据实际情况修改
  36. vector<Edge> v;
  37. for (int i = 0; i < en; i++)for (int j = i + 1; j < en; j++) {
  38. Edge e = { i,j,getLen(i,j) };
  39. v.push_back(e);
  40. }
  41. return v;
  42. }
  43. //计算最小生成树,结果按照边从小到大排序
  44. vector<pair<int, int>> minCostConnectPoints2()
  45. {
  46. vector<Edge> v = getEdge();
  47. sort(v.begin(), v.end(), cmp);
  48. for (int i = 0; i < en; i++)fa[i] = i;
  49. vector<pair<int, int>>ans;
  50. for (int i = 0, j = 0; j < en - 1; i++)
  51. {
  52. if (inSameSet(v[i].a, v[i].b))continue;
  53. merge(v[i].a, v[i].b);
  54. ans.push_back(make_pair(v[i].a, v[i].b));
  55. j++;
  56. }
  57. return ans;
  58. }
  59. class Solution {
  60. public:
  61. int minCostConnectPoints(vector<vector<int>>& points) {
  62. p = points;
  63. en = p.size();
  64. vector<pair<int, int>> v = minCostConnectPoints2();
  65. int ans = 0;
  66. for (pair<int, int> vi : v) {
  67. ans += getLen(vi.first, vi.second);
  68. }
  69. return ans;
  70. }
  71. };

三,Prim

Prim和Dijkstra几乎一样,区别只在于Dijkstra的距离的每个点到起点的路径总长,而Prim的距离就是每个点到最近一个点的距离。

 

 

 

模板代码:


  
  1. const int N = 1000; //点的最大数量
  2. int en; //点的数量
  3. // TODO 用数组或者vector记录点的信息,id要从0开始
  4. vector<vector<int>>p;
  5. bool visit_[N];
  6. int minLen[N];
  7. int getLen(int i, int j) // 计算id为i和j的2个点的距离
  8. {
  9. return 0; // TODO 根据实际情况修改
  10. }
  11. int getStartId()
  12. {
  13. int m = INT_MAX;
  14. int ans = 0;
  15. for (int i = 0; i < en; i++) {
  16. for (int j = 0; j < en; j++) {
  17. if (i != j && m > getLen(i, j)) {
  18. m = getLen(i, j);
  19. ans = i;
  20. }
  21. }
  22. }
  23. return ans;
  24. }
  25. void init()
  26. {
  27. for (int i = 0; i < en; i++) {
  28. minLen[i] = INT_MAX;
  29. visit_[i] = false;
  30. }
  31. minLen[getStartId()] = INT_MIN;
  32. }
  33. int getId()
  34. {
  35. int m= INT_MAX;
  36. int ans = 0;
  37. for (int i = 0; i < en; i++) {
  38. if (!visit_[i] && m > minLen[i]) {
  39. m = minLen[i];
  40. ans = i;
  41. }
  42. }
  43. return ans;
  44. }
  45. void fresh(int id)
  46. {
  47. for (int i = 0; i < en; i++) {
  48. if (!visit_[i])minLen[i] = min(minLen[i], getLen(i, id));
  49. }
  50. }
  51. //计算最小生成树,结果按照边从小到大排序
  52. vector<pair<int, int>> minCostConnectPoints()
  53. {
  54. init();
  55. vector<pair<int, int>>ans;
  56. for (int i = 0; i < en; i++) {
  57. int id = getId();
  58. for (int j = 0; j < en; j++) {
  59. if (visit_[j] && getLen(id, j) == minLen[id]) {
  60. ans.push_back(make_pair(id, j));
  61. break;
  62. }
  63. }
  64. visit_[id] = true;
  65. fresh(id);
  66. }
  67. return ans;
  68. }

时间复杂度:O(V^2),其中V是点的数量。

四,Prim实战

力扣 1584. 连接所有点的最小费用

题目同上


  
  1. const int N = 1000; //点的最大数量
  2. int en; //点的数量
  3. // TODO 用数组或者vector记录点的信息,id要从0开始
  4. vector<vector<int>>p;
  5. bool visit_[N];
  6. int minLen[N];
  7. int getLen(int i, int j) // 计算id为i和j的2个点的距离
  8. {
  9. return abs(p[i][0] - p[j][0]) + abs(p[i][1] - p[j][1]);
  10. }
  11. int getStartId()
  12. {
  13. int m = INT_MAX;
  14. int ans = 0;
  15. for (int i = 0; i < en; i++) {
  16. for (int j = 0; j < en; j++) {
  17. if (i != j && m > getLen(i, j)) {
  18. m = getLen(i, j);
  19. ans = i;
  20. }
  21. }
  22. }
  23. return ans;
  24. }
  25. void init()
  26. {
  27. for (int i = 0; i < en; i++) {
  28. minLen[i] = INT_MAX;
  29. visit_[i] = false;
  30. }
  31. minLen[getStartId()] = INT_MIN;
  32. }
  33. int getId()
  34. {
  35. int m= INT_MAX;
  36. int ans = 0;
  37. for (int i = 0; i < en; i++) {
  38. if (!visit_[i] && m > minLen[i]) {
  39. m = minLen[i];
  40. ans = i;
  41. }
  42. }
  43. return ans;
  44. }
  45. void fresh(int id)
  46. {
  47. for (int i = 0; i < en; i++) {
  48. if (!visit_[i])minLen[i] = min(minLen[i], getLen(i, id));
  49. }
  50. }
  51. //计算最小生成树,结果按照边从小到大排序
  52. vector<pair<int, int>> minCostConnectPoints2()
  53. {
  54. init();
  55. vector<pair<int, int>>ans;
  56. for (int i = 0; i < en; i++) {
  57. int id = getId();
  58. for (int j = 0; j < en; j++) {
  59. if (visit_[j] && getLen(id, j) == minLen[id]) {
  60. ans.push_back(make_pair(id, j));
  61. break;
  62. }
  63. }
  64. visit_[id] = true;
  65. fresh(id);
  66. }
  67. return ans;
  68. }
  69. class Solution {
  70. public:
  71. int minCostConnectPoints(vector<vector<int>>& points) {
  72. p = points;
  73. en = p.size();
  74. vector<pair<int, int>> v = minCostConnectPoints2();
  75. int ans = 0;
  76. for (pair<int, int> vi : v) {
  77. ans += getLen(vi.first, vi.second);
  78. }
  79. return ans;
  80. }
  81. };

文章来源: blog.csdn.net,作者:csuzhucong,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/nameofcsdn/article/details/121004649

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。