在实践中常常会遇到这样的问题:给定n人点,把它们按照一种代价最低的方式连接起来,使得任意两点之间都存在一条路径。
这样的问题可应用在各类网络的设计,包括通信网络、计算机网络、交通网络以及输电网络,从而能够以最低的成本实现网络联通。另外,它也有助于构造旅行商等难题的近似解。
定义:通图的一棵生成树是包含图中的所有顶点的连通无环子图(也就是一棵树)。加权连通图的一棵最小生成树是图的一棵权重最小的生成树,其中,树的权重定义为所有边的权重总和。最小生成树问题就是求一个给定的加权连通图的最小生成树问题。
根据上图构造如下表格:
顶点 | a | b | c | d | e | f |
a | INF | 3 | INF | INF | 6 | 5 |
b | 3 | INF | 1 | INF | INF | 4 |
c | INF | 1 | INF | 6 | INF | 5 |
d | INF | INF | 6 | INF | 8 | 5 |
e | 6 | INF | INF | 8 | INF | 2 |
f | 5 | 4 | 4 | 5 | 2 | INF |
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0xFFFFFFFF //INF代表两点之间不可达
#define n 6 //顶点数量
char v[] = { 'a', 'b', 'c', 'd', 'e', 'f' }; //顶点
struct node
{
int data; //顶点数据
unsigned int lowestcost; //最低成本
}closedge[n]; //Prim算法中的辅助信息
typedef struct
{
int u;
int v;//顶点
unsigned int cost; //边的代价
}Arc; //原始图的边信息
void initialization(int adjMat[][n]) //初始化 邻接矩阵表示法
{
for (int i = 0; i < n; i++) //初始化邻接矩阵,假设所有顶点皆为不可达
for (int j = 0; j < n; j++)
{
adjMat[i][j] = INF;
}
//将图中可抵达的顶点赋值,根据上面的截图表格进行初始化
adjMat[0][1] = 3; adjMat[0][4] = 6; adjMat[0][5] = 5;
adjMat[1][0] = 3; adjMat[1][2] = 1; adjMat[1][5] = 4;
adjMat[2][1] = 1; adjMat[2][3] = 6; adjMat[2][5] = 5;
adjMat[3][2] = 6; adjMat[3][4] = 8; adjMat[3][5] = 5;
adjMat[4][0] = 6; adjMat[4][3] = 8; adjMat[4][5] = 2;
adjMat[5][0] = 5; adjMat[5][1] = 4; adjMat[5][2] = 4;adjMat[5][3] = 5;adjMat[5][4] = 2;
}
int Minmum(struct node * closedge) //返回最小代价边
{
unsigned int min = INF;
int index = -1;
for (int i = 0; i < n;i++) //循环遍历,找到最小边代价返回
{
if (closedge[i].lowestcost < min && closedge[i].lowestcost !=0)
{
min = closedge[i].lowestcost;
index = i;
}
}
return index;
}
void MiniSpanTree_Prim(int adjMat[][n], int s) //Prim算法实现最小生成树
{
for (int i = 0; i < n;i++)
{
closedge[i].lowestcost = INF;
}
closedge[s].data = s; //从顶点s开始
closedge[s].lowestcost = 0;
for (int i = 0; i < n;i++) //初始化辅助数组
{
if (i != s)
{
closedge[i].data = s;
closedge[i].lowestcost = adjMat[s][i];
}
}
for (int e = 1; e <= n -1; e++) //n-1条边时退出
{
int k = Minmum(closedge); //选择最小代价边
cout << v[closedge[k].data] << "--" << v[k] << endl;//加入到最小生成树
closedge[k].lowestcost = 0; //代价置为0
for (int i = 0; i < n;i++) //更新v中顶点最小代价边信息
{
if ( adjMat[k][i] < closedge[i].lowestcost)
{
closedge[i].data = k;
closedge[i].lowestcost = adjMat[k][i];
}
}
}
}
int main()
{
int adjMat[n][n] = {0};
initialization(adjMat); //初始化
cout<<"最小生成树的边为:"<<endl;
MiniSpanTree_Prim(adjMat,0); //Prim算法,从s=1开始.
return 0;
}