关于最小生成树的一种算法,刚刚学习,试着写了一个代码,如有漏洞,请多包涵。
关于Kruskal算法简单解释一下,首先在一个图中,有很多点,同时也有很多边把这些点连起来。
因为每条边都有长度,所以要想求得如何用最小边把所有点连起来,就可以先把边按照从小到大排起来,然后遍历这些边。
但是问题来了,如果有4个点恰好可以被4条最短边连成一个圈的话,就会出现错误,所以要对每个点使用并查集,每遍历一条边,就要从并查集中找一找,这条边所连接的两个点,是不是在同一颗树上,如果是,则跳过;如果不是,就把这两个点加入到同一棵树里。
这样找n-1(假设有n个点)次,就能把所有的点都连在一起,并且所用的线是最短的了。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 1000;
struct stuff{
int from;
int to;
int len;
}point[maxn];
bool cmp(stuff a, stuff b)
{
if(a.len < b.len)
return true;
else
return false;
}
int pre[maxn];
void repre(int m)
{
int i;
for(i=1; i<=m; i++)
{
pre[i] = i;
}
}
bool myfind(int x)
{
int f = point[x].from;
int t = point[x].to;
bool flag = true;
while(flag) //循环查找,直到找到每个点的BOSS
{
if(pre[f] == f && pre[t] == t) //如果找到了各自的BOSS
{
if(f == t) //如果BOSS相同
{
flag = false;
return false;
}
else //如果BOSS不同
{
//cout << f << "->" << t << endl;
pre[f] = t;
//cout <<pre[f]<<" " << pre[t] << endl;
flag = false;
return true;
}
}
else //如果没有找到BOSS
{
f = pre[f];
t = pre[t];
}
}
}
void findpre(int m, int n)
{
int num_m = 0, sum = 0, i=0;
while(num_m < m && i < n)
{
//cout <<"thit is while"<<endl;
if(myfind(i)) //根据BOSS查找来判断这条边连不连
{
//cout << point[i].len << endl;
sum += point[i].len;
num_m++;
}
i++;
}
cout << sum << endl;
}
int main()
{
int n,m, i;
scanf("%d%d", &m, &n); //输入m个点和n条边
repre(m); //进行并查集的重置;
for(i=0; i<n; i++) //输入
{
scanf("%d%d%d", &point[i].from, &point[i].to, &point[i].len);
}
sort(point, point+n, cmp); //排序
findpre(m, n); //开始查找最小生成树
return 0;
}