贪婪算法——Prim 算法

在实践中常常会遇到这样的问题:给定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;
}

猜你喜欢

转载自blog.csdn.net/zmeilin/article/details/81181005