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

来源:互联网 发布:充电数据监控 编辑:程序博客网 时间:2024/06/07 10:46

最小生成树

一个有 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;}

测试数据

50 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