图论算法——Kruskal算法

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

posted @ 2017-06-27 22:01  leo101  阅读(253)  评论(0编辑  收藏  举报