有n个城市,每个城市距离不等 ,需要把他们连起来,要求从一个 城市可以走到所有其他的城市,且路的长度要求最少(权值最小)。
这个时候,就需要构造最小生成树了。(n个城市需要n-1条边)。 我们在这里介绍两种算法,每种算法都有自身的优势,我们放在最后讨论。
解决方案
(—)Kruskal算法
构成生成树的准则有三条:
<1> 必须只使用该网络中的边来构造最小生成树。
<2> 必须使用且仅使用n-1条边来连接网络中的n个顶点
<3> 不能使用产生回路的边。
step:
<1> 有n个城市,则用数组point[n]来表示,
n个城市最多有 n*(n-1)/2 条边, 所以需要创建 n*(n-1)/2个这样的结构体。
struct edge
{
int begin; //这条边 左边的城市编号
int weight; //这条边的长度
int end; //这条边 右边的城市编号
}set[n*(n-1)/2];
并输入数据
for(int i = 0; i < n*(n-1)/2; ++i)
scanf("%d%d%d", &set[i].begin, &set[i].end, &set[i].weight);
<2> 用sort 给 这些的结构体按 边的长度 从小到大 排序
sort(set, set+tmp, cmp );
<3> 遍历这些结构体,用并查集判断每个结构体中的 左边城市 和 右边城市的根 是否相同
不同, 则合并左城市与右城市,并且,ans += 这条边的长度。
相同, 什么也不做(不合并,因为最小生成树,已经连通的城市没必要再浪费金钱去联通)。
init(); //初始化并查集
for(int i = 0; i < n*(n-1)/2; ++i)
if( find(set[i].begin) != find(set[i].end))
{
Union(set[i].begin, set[i].end);
ans += set[i].weight;
}
return ans;
<4> 如果已经达到了 n-1条边,那么最小生成树一定已经完成。所以可以这样剪 枝
init(); //初始化并查集
int count = 0;
for(int i = 0; i < n*(n-1)/2 && count != n-1; ++i)
if( find(set[i].begin) != find(set[i].end))
{
Union(set[i].begin, set[i].end);
ans += set[i].weight;
count++;
}
return ans;
完整代码如下:
#include <algorithm>
#include <cstdio>
#define max 10005
using namespace std;
int n, tmp;
int point[max];//用来表示每个点,以供并查集操作
struct edge
{
int begin;
int weight;
int end;
}set[max];
bool cmp(const edge& a, const edge& b)
{
return a.weight < b.weight;
}
int find(const int& index)
{
return point[index] = point[index] == index?index:find(point[index]);
}
void Union(const int& a,const int& b)
{
point[find(a)] = find(b);
}
void init()
{
for(int i = 0; i <= n; ++i) //这里,可是 坑 了我一次又一次啊,必须是 i= 0到i<=n,而不是i=0到i < n;
point[i] = i;
}
int krustal()
{
int ans = 0;
sort(set, set+tmp, cmp );
init(); //初始化并查集
for(int i = 0; i < tmp; ++i)
if( find(set[i].begin) != find(set[i].end))
{
Union(set[i].begin, set[i].end);
ans += set[i].weight;//这个版本为未剪枝的版本
}
return ans;
}
int main()
{
while( ~scanf("%d", &n) && n )
{
tmp = n*(n-1)/2;
for(int i = 0; i < tmp; ++i)
scanf("%d%d%d", &set[i].begin, &set[i].end, &set[i].weight);
printf("%d\n", krustal() ); } return 0;}