数据结构实验之图论六:村村通公路

悠悠 2022-04-12 14:24 357阅读 0赞

Problem Description

当前农村公路建设正如火如荼的展开,某乡镇政府决定实现村村通公路,工程师现有各个村落之间的原始道路统计数据表,表中列出了各村之间可以建设公路的若干条道路的成本,你的任务是根据给出的数据表,求使得每个村都有公路连通所需要的最低成本。

Input

连续多组数据输入,每组数据包括村落数目N(N <= 1000)和可供选择的道路数目M(M <= 3000),随后M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个村庄的编号和修建该道路的预算成本,村庄从1~N编号。

Output

输出使每个村庄都有公路连通所需要的最低成本,如果输入数据不能使所有村庄畅通,则输出-1,表示有些村庄之间没有路连通。

Sample Input

5 8
1 2 12
1 3 9
1 4 11
1 5 3
2 3 6
2 4 9
3 4 4
4 5 6

Sample Output

19

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #define INF 0x3f3f3f3f
  5. #define N 1100
  6. int map[N][N]; //邻接矩阵存储图
  7. int dis[N]; //记录当前树与所有结点的最小距离
  8. int vis[N]; //记录结点是否被遍历过
  9. int sum, n, m;//n代表节点数 sum保存生成树的权值总和
  10. void prim()
  11. {
  12. sum=0; //最小生成树的权值总和初始化为0
  13. int mm;
  14. memset(vis, 0, sizeof(vis)); //初始化节点均没有被访问
  15. int i,j;
  16. for(i = 1; i <= n; i++)
  17. {
  18. dis[i] = map[1][i]; //我们从1号节点开始生成树
  19. }
  20. vis[1] = 1; //生成树的根(起点)标记访问
  21. int pos; //用来记录每一次循环找到的节点的编号
  22. int d = 0; //标记变量
  23. for(i = 1; i < n; i++) //要生成n-1条边,所以循环n-1次
  24. {
  25. mm = INF;
  26. for(j = 1; j <= n; j++) //对dis数组进行遍历,找到值最小的
  27. {
  28. if(!vis[j] && dis[j] < mm)//满足没有被遍历过,并且距离小于最大值
  29. {
  30. mm = dis[j];
  31. pos = j;
  32. }
  33. }
  34. if(mm == INF) //也就意味着中间有断点,不能连通
  35. {
  36. d = 1;
  37. break;
  38. }
  39. sum =sum+ mm; //加上找到的最小权值
  40. vis[pos] = 1; //标记找到的该节点被访问
  41. for(j = 1; j <= n; j++) //更新dis数组
  42. {
  43. if(!vis[j] && dis[j] > map[pos][j])//满足没有被遍历过,并且新增点到其他点的距离小于当前存储的最小距离
  44. {
  45. dis[j] = map[pos][j]; //距离更新
  46. }
  47. }
  48. }
  49. if(d == 0)
  50. {
  51. printf("%d\n", sum);//n-1次循环完毕后输出权值总和
  52. }
  53. else
  54. {
  55. printf("-1\n");
  56. }
  57. }
  58. int main()
  59. {
  60. while(scanf("%d %d",&n,&m)!=EOF)
  61. {
  62. int i,j;
  63. for(i = 1; i <= n; i++)
  64. {
  65. for(j = 1; j <= n; j++) //对mp数组初始化
  66. {
  67. if(i == j)
  68. {
  69. map[i][j] = 0;
  70. }
  71. else
  72. {
  73. map[i][j] = INF;
  74. }
  75. }
  76. }
  77. while(m--)
  78. {
  79. int a, b, c;
  80. scanf("%d %d %d", &a, &b, &c);
  81. if(map[a][b] > c) //如果存在重边,取最小值
  82. {
  83. map[a][b] = map[b][a] = c;
  84. }
  85. }
  86. prim(); //执行普利姆算法
  87. }
  88. return 0;
  89. }

我们来看一下dis是如何更新的:
首先当树中只有一号的那时候
dis
0 1 2 3 4 5
0 0 12 9 11 3 存入一号时,取最小5号
0 0 12 9 6 0 存入5号时,取最小4号
0 0 12 4 0 0 存入4号时,取最小3号
0 0 6 0 0 0 存入3号时,取最小2号

在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,357人围观)

还没有评论,来说两句吧...

相关阅读