Prim算法
概述
最小生成树是指树结点的权值之和最小。Prim算法是根据贪心法的思想实现的。
贪心策略
从相邻结点中选择最小权重的结点
思路
思路:首先选择跟结点,初始化根结点到各结点的距离( El),将与最小权值的结点进行连接。
其次,判断加入新的结点后已连接结点到未连接结点的最小权值是否发生变化,更新最小权值
最后,重复上述过程直到所有结点都已经连接。
补充知识点
// 补充知识点:结构体 struct
//C++ 语言中结构体的两种使用方法
// 1、不带tyepdef
struct Str
{
int a = 1;
int b;
} Str1;
//Str1是结构体 Str 的一个变量,可以直接使用 Str.a
// 2、带tyepdef
typedef struct type
{
int a = 2;
int b;
} Type1;
//Type1是一个别名,需要声明一个变量: Type1 TT; 然后使用 TT.a; 其中 Type 可以省略
总结
整个算法分为三部分:初始化、选择最小权重、调整权重。
代码分析及用例
#include <iostream>
#include <algorithm>
using namespace std;
const int inf = 1000; //代表无线距离,没有连接
int map[100][100]; //各边关系
//补助数组的结构体
typedef struct
{
int lowcost; //权值
int adjvex; //与其相邻的结点
}Element;
// Prim算法
//参数1:结点个数
//参数2:根结点
void Prim(int n,int w)
{
int temp; //记录新加入的结点
Element El[10]; //声明一个结构体变量数组,假设最多有10个结点
//初始化根结点与各结点的关系
for(int i = 0; i < n; i++)
{
El[i].lowcost = map[w][i]; //与结点 i 之间的权值
El[i].adjvex = w; //与结点 i 相邻的结点
}
//将根结点加入树
El[w].lowcost = 0; //权值为 0 表示已经连接不需要在判断
// Prim算法的主体部分
//将剩下的所有结点遍历加入树
for(int i = 0; i < n-1;i++)
{
int min = 1000; //最小的权值
temp = 100;
//遍历未连接结点 的权值,找到最小权值
for(int j = 0; j < n; j++)
{
//如果该结点还没有加入树,并且它与已经加入树的结点之间的权值 最小
if(El[j].lowcost != 0 && El[j].lowcost < min)
{
min = El[j].lowcost; //更新最小权值
temp = j; //记录最小权值的结点
}
}
//输出最小生成树的边。 El[k].adjvex为与 k 结点连接的结点
cout << El[temp].adjvex << "------" << temp << endl;
El[temp].lowcost = 0; //将 temp 结点加入树
//根据新加入的结点 temp 调整与未加入树的结点之间最小权值
for(int j = 0; j < n; j++)
{
if(map[temp][j] < El[j].lowcost)
{
El[j].lowcost = map[temp][j];
El[j].adjvex = temp;
}
}
}
}
int main(int argc, char** argv) {
/* 测试用例
6 9
0 1 34
0 5 19
0 2 46
1 4 12
2 3 17
2 5 25
3 5 25
3 4 38
4 5 26
*/
int n ,m;
int a,b,c;
while(cin>>n>>m)
{
//对图进行初始化
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
if(i == j) map[i][j] = 0;
else map[i][j] = inf;
//边与边的关系
for(int i = 0; i < m; i++)
{
cin >> a >> b >> c;
map[a][b] = map[b][a] = c;
}
Prim(n,0);
}
system("pause");
return 0;
}