Bootstrap

克鲁斯卡尔算法,公路村村通

 代码以

公路村村通

作者 陈越

单位 浙江大学

现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。

输入格式:

输入数据包括城镇数目正整数 n(≤1000)和候选道路数目 m(≤3n);随后的 m 行对应 m 条道路,每行给出 3 个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从 1 到 n 编号。

输出格式:

输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出 −1,表示需要建设更多公路。

 为例



#include<bits/stdc++.h>

using namespace std;

const int N = 20010;

int p[N];//标记这个节点的源/根

int sum=0, cnt=0;//权重的和,已连接的边数



int n, m;//节点数,预选边的数

// 结构体

struct road {

  int x, y;//两个节点上的数

  int w;//边的权重



}r[N];//简写



bool cmp(road x,road y) {

  return x.w < y.w;

}//比较函数,返回权重小的结构体



int find(int x) {//溯源,找到当前节点的根,判断是否构成回路



  if (x != p[x]) x = find(p[x]);//递归溯源

  return p[x];



}



int krusal() //核心算法

{

  for (int i =0; i < m; i++) {//遍历结构体数组

    int a =r[i].x;

    int b = r[i].y;

    int c = r[i].w;



    int aa = find(a);

    int bb = find(b);



    if (aa != bb) {//判断源/根是否相同



      p[aa] = b;//如果不同,合并为一个集合

      sum += c;//权重加和

      cnt++;//边+1



    }

  }



  if (cnt < n - 1) return -1;//对于个节点,想要“村村通”,至少要有n-1条边

  else return sum;//返回权重

}



int main()

{



  cin >> n >> m;

  for (int i = 1; i <= n; i++) p[i] = i;//开始时,各个节点分别独立

  //后面通过赋值的方式,将它们看作一个集合

  //比如:

  //p[1]=3;

  //相当于v1这个点与3连接了,3可以看作是它的根

  for (int i = 0; i < m; i++) {

    int a, b, c;

    cin >> a >> b >> c;

    r[i] = { a,b,c };

  }

  sort(r,r+m, cmp);



  int t=krusal();



  if (t == -1) cout << -1;

  else cout << t;



  return 0;

}

;