prim算法求最小生成树

例题链接

最小生成树的含义是,假设给定n个点,m条边(m > n - 1),在m条边中选择n - 1条边将n个点连接成一个连通图,即一棵生成树。因为每个边都有一个权重,当选择的边权和最小时产生的生成树被称为最小生成树,边权和就是这棵最小生成树对应的权值

求最小生成树的策略为:每次从所有没选中的点中中选出到这个生成树集合的权值最小的点,直到所有点全部被选中。第一轮循环就是选择了一个点作为整棵生成树的第一个点去更新其它点到这个生成树集合的距离,然后再进行后面的循环。因为边权可能是负数,所以再除了第一次循环以外再循环出来了的最小值为无穷就需要直接返回INF告诉主函数无法构成一棵最小生成树

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 510, INF = 0x3f3f3f3f;
int n, m, k;
int g[N][N];
int dist[N];
bool st[N];
int prim()
{
    memset(dist, 0x3f, sizeof(dist));//初始化各个点到生成树的距离为无穷
    int res = 0;//存边权和
    for (int i = 0; i < n; i++)
    {
        int t = -1;
        for (int j = 1; j <= n; j++)
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;
        if (i && dist[t] == INF)//除了第一次循环出来的最小边是无穷,后面再循环出来最小值为无穷的话则无法构成一棵生成树
            return INF;
        if (i)
            res += dist[t];
        for (int j = 1; j <= n; j++)
            dist[j] = min(dist[j], g[t][j]);//更新每个点到这个生成树集合的距离
        st[t] = true;//标记这个点走过了
    }
    return res;
}
int main()
{
    scanf("%d %d", &n, &m);
    memset(g, 0x3f, sizeof(g));
    while (m --)
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        g[a][b] = g[b][a] = min(g[a][b], c);//存储边权值
    }
    int t = prim();
    if (t == INF)
        printf("impossible");
    else
        printf("%d\n", t);
    return 0;
}
posted @ 2022-07-15 21:07  LYL233  阅读(78)  评论(0)    收藏  举报