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

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 winoros


vector<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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值