(最小生成树)prim算法

思想参考:

https://subetter.com/articles/2018/05/prim-algorithm.html

总结一下:
如果选 0为起点,low_cost[i]表示以 0这个起点到i 这个终点的权值,我们找最小的权值的终点i,然后以i为起点,去更新low_cost[]这个数组,如果与i相连的数是j,现在有两种情况,j与0相连,j与i相连但不与0相连。如果j也与0相连,我们找0到j和i到j这两者的最小距离,然后用这个最小的距离更新low_cost[j]。如果j不与0相连,那么就直接填上low_cost[j]

代码分析一下:

matrix[i][j]=m意思是以i为起点j为终点的权值为m
path[i]=a,意思是i起点连的是a终点
由此我们可见数组可以表达的意思可以是那几个变量之间的相关性

visit数组存的是目前最小生成树上已经有的结点,我们最小生成树最终是要有所有的结点的

先找一个起点,然后把与起点相连的路径都存到low_cost里

找一个终点,起点到他的权值最小,将这个终点进行标记(证明已经将其加入到最小生成树里面了),并且记录最小路径和的sum要加上他的权值

由于low_cost目前只存了与起点相连的路径,现在最小生成树里面加入了一个新的结点,那么我们就需要更新low_cost数组,把与这个新的结点相连的路径加入到low_cost数组里,路径就要考虑终点,这个终点一定不是在最小生成树里的,所以要用到visit数组,然后如果matrix[min_cost_index][j]就是这个新节点到某一终点的权值比low_cost[j]小的话,就更新low_cost[j]

#include <iostream>

using namespace std;

int  matrix[100][100]; // 邻接矩阵
bool visited[100];     // 标记数组
int  low_cost[100];    // 边的权值
int  path[100];        // 记录生成树的路径
int  source;           // 指定生成树的起点
int  vertex_num;       // 顶点数
int  edge_num;         // 边数
int  sum;              // 生成树权和

void Prim(int source)
{
    memset(visited, 0, sizeof(visited));
    visited[source] = true;
    for (int i = 0; i < vertex_num; i++)
    {
        low_cost[i] = matrix[source][i];
        path[i] = source;
    }

    int min_cost;       // 权值最小
    int min_cost_index; // 权值最小的下标
    sum = 0;
    for (int i = 1; i < vertex_num; i++) // 除去起点,还需要找到另外 vertex_num-1 个点
    {
        min_cost = INT_MAX;
        for (int j = 0; j < vertex_num; j++)
        {
            if (visited[j] == false && low_cost[j] < min_cost) // 找到权值最小
            {
                min_cost = low_cost[j];
                min_cost_index = j;
            }
        }

        visited[min_cost_index] = true;  // 该点已找到,进行标记
        sum += low_cost[min_cost_index]; // 更新生成树权和

        for (int j = 0; j < vertex_num; j++) // 从找到的最小下标更新 low_cost 数组
        {
            if (visited[j] == false && matrix[min_cost_index][j] < low_cost[j])
            {
                low_cost[j] = matrix[min_cost_index][j];
                path[j] = min_cost_index;
            }
        }
    }
}

int main()
{
    cout << "请输入图的顶点数(<=100):";
    cin >> vertex_num;
    cout << "请输入图的边数:";
    cin >> edge_num;

    for (int i = 0; i < vertex_num; i++)
        for (int j = 0; j < vertex_num; j++)
            matrix[i][j] = INT_MAX; // 初始化 matrix 数组

    cout << "请输入边的信息:\n";
    int u, v, w;
    for (int i = 0; i < edge_num; i++)
    {
        cin >> u >> v >> w;
        matrix[u][v] = matrix[v][u] = w;
    }

    cout << "请输入起点(<" << vertex_num << "):";
    cin >> source;
    Prim(source);

    cout << "最小生成树权和为:" << sum << endl;
    cout << "最小生成树路径为:\n";
    for (int i = 0; i < vertex_num; i++)
        if (i != source)
            cout << i << "----" << path[i] << endl;

    return 0;
}
/*
请输入图的顶点数(<=100):5
请输入图的边数:7
请输入边的信息:
0 1 8
0 2 3
0 3 2
1 3 3
3 2 4
2 4 1
3 4 5
请输入起点(<5):0
最小生成树权和为:9
最小生成树路径为:
1----3
2----0
3----0
4----2
*/

猜你喜欢

转载自blog.csdn.net/qq_40828914/article/details/81564856