您的位置:首页 > 其它

图论算法——Kruskal算法

2017-06-27 22:00 155 查看
Kruskal 算法是针对最小生成树的一个算法,不优化的时间复杂度是O(e^2),用并查集优化的时间复杂度就是O(eloge)其中e为边数。

所以就可以看出,并查集对Kruskal的优化还是很大的。

我们先来看看Kruskal针对的到底是一个什么样的问题:

•输入一个有权无向连通图G,在已有的边中删掉尽可能多的边得到一个新的图G’。使得G’依旧是连通图并且剩余的边权值之和最小,请输出G’中所有边权之和。

所以说,最小生成树虽然是“树”,但这却是一个有关图论的问题。

Q:树怎么能跟图扯到一起呢?

A:树其实就是一个特殊的图,也就是树是一个没有环的图

Q:但问题中并没有提到“没有环”啊?

A:这就是问题的关键所在。

我们先来回答几个问题:

Q:问题中的Q’里不能有什么?

A:不能有环!

Q:为什么不能有环?

A:因为在一个在Q’中所有的环里的很多边都是多余的,为什么这么说么?看看下面这张图就知道了!



你看出什么了吗?这就是之前那个问题的答案!在Q’中是肯定不能有环的!有环也可以拆掉,只要保持联通就可以了。没有环的图就是什么?树!

解决了这些疑惑,就可以开始Kruskal算法了,Kruskal算法的步骤是:

1、 将G中所有点之间的边断开得到G’,然后将所有边按照权值从小到大排序不妨记为边集E。

2、 集合E中当前权值最小的边记为e,将e从E中删除。

3、 如果e连接的顶点v和u在G’中已经连通,转2。

这一点也就是并查集所能优化的一点,并查集可以判断这两个节点是否已经联通,如果你不知道并查集怎么用,有请戳并查集帮助1(戳我)并查集帮助2(戳我)

4、 将e,加入G’

5、 如果G’中边的数量等于n-1,算法结束,否则转2。

详见代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>

class edge
{
public:
int u;
int v;
int weight;
};

bool operator< (const edge& a,const edge& b)
{
return a.weight<b.weight;
}

std::vector<edge> edges;
int father[1001];

int get_father(int x)
{
if(father[x]==x)return x;
return father[x] = get_father(father[x]);
}

int main()
{
int n,m;
std::cin>>n>>m;
edges.resize(m+1);
for(int i = 0;i<m;i++)
std::cin>>edges[i].u>>edges[i].v>>edges[i].weight;
std::sort(edges.begin(),edges.end());
for(int i = 0;i<n;i++)father[i] = i;
int ans = 0;
for(int i = 0;i<m;i++)
{
if(get_father(edges[i].u)==get_father(edges[i].v))continue;
ans += edges[i].weight;
father[get_father(edges[i].u)] = father[get_father(edges[i].v)];
}
std::cout<<ans;
return 0;
}


如果代码有问题,欢迎留言!

这里有几个初学者不会很知道的东西,给出几个帮助:

vector:vector帮助1(戳我)vector帮助2(戳我)

sort:sort帮助1(戳我)

operator:帮助1
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息