求解最小生成树的算法 prim算法(附模板)

来源:互联网 发布:伺服控制系统编程 编辑:程序博客网 时间:2024/06/03 12:29

kruskal算法的链接 http://blog.csdn.net/winoros/article/details/21279967


接下来是prim算法。prim算法和kruskal算法同样是贪心,不过贪心的思路不同。


prim算法的步骤如下

1)标记任意一个点。

2)然后找一条边权最小的而且是一端被标记,另一端未被标记的边加进来。也就加入合法的最短边,然后将该边为被标记的顶点标记

3)这样进行到所有点都被标记即为结束。


算法的正确性个人感觉可以利用数学归纳法证明。证明如下

1)只有两个点标记时,明显该边边权必为最小。

2)假设有k个点被标记时,所加入的边了这k个点的最小生成树。

3)由于再加入的时候选取的是与现有生成树相连的边权最小的边,所以这时的k个边构成了这k+1个的最小生成树。

4)从而当所有点都被标记时所得边即构成了这张图的最小生成树。

具体的算法实现中,我们用一个bool数组marked[i]标记点i是否已计入最小生成树中,一个int数组dis[i]来表示未标记的点i加入最小生成树的最小权值(也就是点i到已标记的点最小的距离)


prim算法可以用堆优化,这里没有使用,只用邻接表实现。这里复杂度为O(N^2)(N为顶点的个数),相对于kruskal,prim算法更适合求稠密图,因为prim的复杂度与边的个数没有关系。

下面是代码

//made by winorosvector<pair<int, int> > v[MAX_N];bool marked[MAX_N];int dis[MAX_N];int prim(int n) {    memset(marked, 0, sizeof(marked));    fill(dis, dis + n, INT_MAX);//这里顶点的标记总0开始    dis[0] = 0;    int ans = 0;    for(int i = 0; i <= n;  i++) {        int mark = -1;        for(int j = 0; j <= n; j++) {            if(!marked[j]) {//这个if是在找最小的dis[j]                if(mark == -1) mark = j;                else if(dis[j] < dis[mark]) mark = j;            }        }        if(mark == -1) break; //如果已经无点可找(也就是所有的点都已进入最小生成树中),跳出循环        marked[mark] = true;        ans += dis[mark];        for(int j = 0; j < v[mark].size(); j++) {//这个for是更新剩余点到最小生成树的距离            if(!marked[v[mark][j].first]) {                int x = v[mark][j].first;                dis[x] = min(dis[x],v[mark][j].second);            }        }    }    return ans;}


0 0
原创粉丝点击