Prim算法:用来解决最小生成树的问题
Prim算法和Dijkstra算法思想类似,都是采用贪心的思想。
两个算法的主要区别:
-
Dijkstra算法的dis[]数组是记录未访问结点集合与源结点的最短路径,而Prim算法的dis[]数组记录的是未访问结点集合到已访问结点结合的最短距离。
两个算法都是用bool visited[]数组来表示当前结点是否被访问。 -
Prim算法有一个统计最小生成树的总的最短距离len,每次访问一个距离最短的结点,都要将该最短边加上len,而Dijkstra算法则没有该变量。
-
Prim算法是求解最小生成树的算法,比如用来求解N个村庄之间修路的最小花费,而Dijkstra算法是求解单源最短路径的算法,比如求解某一个村庄到所有村庄的最短路径。
算法的具体步骤:
1、除了指定根结点外,其他的结点的dis[]都设置为INF(无穷大)
2、遍历n次,n为图中的结点数。每次都找出未被访问结点距离已访问结点集合的最小值。
3、遍历当前结点所邻接的未被访问的边,如果以当前结点作为中介点,使得其邻接点到已访问集合的距离更短。则更新距离。
样例:
输入:
6 10//6个顶点,10条边。以下10行为10条边
0 1 4//边0->1与1->0的边权为4,下同
0 4 1
0 5 2
1 2 6
1 5 3
2 3 6
2 5 5
3 4 4
3 5 5
4 5 3
输出:
15
下面为实现代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int prim_max_num = 1000;
const int INF = 1000000000;
int n, m, G[prim_max_num][prim_max_num];
int dis[prim_max_num]; //顶点与集合S的最短距离
bool visited[prim_max_num] = {false};
//求出最小生成树的最短距离
int prim()
{
//默认根结点为 0
fill(dis, dis + prim_max_num, INF); //初始化 dis 数组
dis[0] = 0;
int result = 0;
for (int i = 0; i < n; i++)
{ //共有 n 个结点
int index = -1; //最短路径结点的下标
int min = INF;
for (int j = 0; j < n; j++)
{
if (visited[j] == false && dis[j] < min)
{
index = j;
min = dis[j];
}
}
//找不到最小结点
if (index == -1)
{
return -1;
}
visited[index] = true;
result += dis[index];
for (int k = 0; k < n; k++)
{
if (visited[k] == false && G[index][k] != INF && G[index][k] < dis[k])
{
dis[k] = G[index][k];
}
}
}
return result;
}
int main()
{
cin >> n >> m;
fill(G[0], G[0] + prim_max_num * prim_max_num, INF);
int from_node, to_node, weight;
for (int i = 0; i < m; i++)
{
cin >> from_node >> to_node >> weight;
G[from_node][to_node] = G[to_node][from_node] = weight;
}
int result = prim();
cout << result << endl;//输出最短距离
system("pause");
return 0;
}
运行结果: