Agri-Net POJ - 1258C++(并查集+Kruskal)

Farmer John has been elected mayor of his town! One of his campaign promises was to bring internet connectivity to all farms in the area. He needs your help, of course.

Farmer John ordered a high speed connection for his farm and is going to share his connectivity with the other farmers. To minimize cost, he wants to lay the minimum amount of optical fiber to connect his farm to all the other farms.

Given a list of how much fiber it takes to connect each pair of farms, you must find the minimum amount of fiber needed to connect them all together. Each farm must connect to some other farm such that a packet can flow from any one farm to any other farm.

The distance between any two farms will not exceed 100,000.
Input

   The input includes several cases. For each case, the first line contains the number of farms, N (3 <= N <= 100). The following lines contain the N x N conectivity matrix, where each element shows the distance from on farm to another. Logically, they are N lines of N space-separated integers. Physically, they are limited in length to 80 characters, so some lines continue onto others. Of course, the diagonal will be 0, since the distance from farm i to itself is not interesting for this problem.
   Output
    
  
   For each case, output a single integer length that is the sum of the minimum length of fiber required to connect the entire set of farms.
   Sample Input
    4

0 4 9 21
4 0 8 17
9 8 0 16
21 17 16 0
Sample Output
28
问题简述:具有多个案例,首先输入农村数量。然后在接下来的每一行输入从第一个村庄到另一个村庄所需的光纤量。最后输出连接所有村庄所需的最小光纤量。

问题分析:这道题主要是求最小生成树,即最小光纤量,可采用并查集和克鲁斯卡尔算法

#include <iostream>
#include<algorithm>
using namespace std;
const int N=100;    //最大村庄数
//并查集
int f[N+1];      
void UNInit(int n)   //把每一个村庄用f[i]表示,其中f[i]=i是初始值,i表示各个村庄,f[i]的值在合并村庄时会改变,
{                    //合并一个村庄,f[i]的值会被同化一个,当所有村庄都连接了,即f[1]=[2]=...f[n].
 for (int i = 1; i <= n; i++)
 {
  f[i] = i;
 }
}            
int Find(int a)     //a表示村庄,此函数的作用是寻找村庄a的f[a]值,若f[a]值不是a,表示a已被合并
{
 if (a == f[a])
 {
  return a;
 }
 else
 {
  return Find(f[a]);  //理解此处要与下面的Union中的if语句内容结合,此处返回值是所有和并村庄所带表的值f[i],这些合并村庄中唯一一个f[i]=i的村庄,
 }
}
bool Union(int a, int b) //判断村庄a和b是否合并
{
 a = Find(a);
 b = Find(b);
 if (a != b)  //a与b未合并
 {
  f[a] = b;     //令f[a]等于Find(b),即b所在合并村庄所代表的值
  return true;   
 }
 else
 {
  return false;  //已合并,返回false
 }
}
//克鲁斯卡尔算法
struct road
{
 int n,v,f;   //n,v分别为n村庄和v村庄,f为n,v之间所需的光纤量
}roads[N*N];
bool cmp(road a,road b)   //为后面排序时做准备
{
 return a.f < b.f;    //排序条件
}
int main()
{
 int n;     //村庄数
 int p = 0;  //总路数
 int f;      //光纤量
 while (cin >> n)
 { 
  UNInit(n);  //令f[i]=i
  for (int i = 1; i <=n; i++)
  {
   for (int j = 1; j <=n; j++)
   {
    cin >> f;     
    if (j > i)    //避免出现同村庄(i到i)或两条同样的路(i到j和j到i)
    {
     roads[p].n = i;
     roads[p].v = j;
     roads[p++].f=f;  //把所有路放进数组
    }
   }
  }
  int sum = 0;  //总光纤量
  sort(roads, roads + (n*n-n)/2, cmp);  //排序,把所有路按所需光纤量的大小排序,有少到多
  for (int i = 0; i <(n*n - n) / 2;i++)
  {
   if (Union(roads[i].n, roads[i].v))  //判断是否 已经合并,未合并返回true,合并返回false.
    sum += roads[i].f;   //随i的增大,每一条路所需光纤量也增大,故先比较小光纤量的路,把符合条件的最小光纤量的路连接。
  }
  cout<<sum<<endl;
  }
  return 0;
  }
发布了27 篇原创文章 · 获赞 16 · 访问量 1908

猜你喜欢

转载自blog.csdn.net/weixin_43979090/article/details/88900382