算法基础 - 最小生成树(Prim算法)

最小生成树

一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边

Prim算法

普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小。该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现;并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现;1959年,艾兹格·迪科斯彻再次发现了该算法。因此,在某些场合,普里姆算法又被称为DJP算法、亚尔尼克算法或普里姆-亚尔尼克算法。

流程表格

图例解释集合
step_1初始图{}
step_2顶点D被任意选为起始点。顶点A、B、E和F通过单条边与D相连。A是距离D最近的顶点,因此将A及对应边AD以高亮表示。{D}
step_3下一个顶点为距离D或A最近的顶点。B距D为9,距A为7,E为15,F为6。因此,F距D或A最近,因此将顶点F与相应边DF以高亮表示。{D, A}
step_4下一个顶点为距离D或A最近的顶点。B距D为9,距A为7,E为15,F为6。因此,F距D或A最近,因此将顶点F与相应边DF以高亮表示。{D, A, F}
… step 5 6 7以此类推{…}
step_7顶点G是唯一剩下的顶点,它距F为11,距E为9,E最近,故高亮表示G及相应边EG。{D, A, F, B, E, C }
step_8现在,所有顶点均已被选取,图中绿色部分即为连通图的最小生成树。在此例中,最小生成树的权值之和为39。{D, A, F, B, E, C, G }

如何求最短路径

  1. 输入一个图
  2. 维护一个lowcost[v]的数组,是当前已知节点到其他所有节点的最短距离。
  3. 每次从lowcost中找到最短的(不能添加已经添加过的节点),然后添加到已知节点里,然后更新lowcost
  4. 重复直到所有节点都已知。

Prim代码实现

//
//  main.cpp
//  HiHocoder
//
//  Created by Alps on 16/5/9.
//  Copyright © 2016年 chen. All rights reserved.
//
#include <iostream>
#include <cstring>
#include <string>
#include <vector>

using namespace std;

int graph[1002][1002]; //节点最大1001个
int lowcost[1002];
int flag[1002] = {0};

int findMin(int T){
    int mnLen = -1, mnNode = -1;
    for(int i = 0; i < T; i++){
        if(flag[i] == 0 && (mnLen == -1 || mnLen > lowcost[i])){
            mnLen = lowcost[i];
            mnNode = i;
        }
    }
    if (mnNode == -1) {
        return -1;
    }
    for(int i = 0; i < T; i++){
        lowcost[i] = min(lowcost[i], graph[mnNode][i]);
    }
    flag[mnNode] = -1;
    return mnLen;
}

long Prim(int graph[][1002], int T, int start){
    flag[start] = -1;
    for(int i = 0; i < T; i++){
        lowcost[i] = graph[start][i];
    }
    long ans = 0;
    while(1){
        int mn = findMin(T);
        if(mn == -1) break;
        ans += mn;
    }
    return ans;
}

int main(){
    int T;
    cin>>T;
    for(int i = 0; i < T; i++){
        for(int j = 0; j < T; j++){
            cin>>graph[i][j];
        }
    }
    long len = Prim(graph, T, 0);
    cout<<len<<endl;
    return 0;
}

测试数据

5
0 1005 6963 392 1182 
1005 0 1599 4213 1451 
6963 1599 0 9780 2789 
392 4213 9780 0 5236 
1182 1451 2789 5236 0 

输出:
4178
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值