• 858. Prim算法求最小生成树


    858. Prim算法求最小生成树 - AcWing题库

    给定一个 n 个点 m 条边的无向图,图中可能存在重边和自环,边权可能为负数。

    求最小生成树的树边权重之和,如果最小生成树不存在则输出 impossible

    给定一张边带权的无向图 G=(V,E),其中 V 表示图中点的集合,E 表示图中边的集合,n=|V|,m=|E|。

    由 V 中的全部 n 个顶点和 E 中 n−1 条边构成的无向连通子图被称为 G 的一棵生成树,其中边的权值之和最小的生成树被称为无向图 G 的最小生成树。

    输入格式

    第一行包含两个整数 n 和 m。

    接下来 m 行,每行包含三个整数 u,v,w,表示点 u 和点 v 之间存在一条权值为 w 的边。

    输出格式

    共一行,若存在最小生成树,则输出一个整数,表示最小生成树的树边权重之和,如果最小生成树不存在则输出 impossible

    数据范围

    1≤n≤500,
    1≤m≤105,
    图中涉及边的边权的绝对值均不超过 1000010000。

    输入样例:
    1. 4 5
    2. 1 2 1
    3. 1 3 2
    4. 1 4 3
    5. 2 3 2
    6. 3 4 4
    输出样例:
    6

     解析:


    prim算法的基本想法:种一棵树,让树从一个节点增长到n个节点
    1.初始的时候树只有一个节点,没有边,初始节点可以是任意一个节点
    2.每一轮循环找出一条边把它接到树上
    3.整个过程都要保证一个性质:
            树是连通图
            没有回路
    4.算法循环次数等于节点数量(每一轮循环添加一个节点)

    具体操作:
    1.树中只有一个节点(任意选这一个节点即可),没有边。
    2.用集合 U 来保存选中的节点
    3.用集合 T 来保存树的边
    4.每次循环把一个点和一条边接到树上:
        e(u,v)表示:边的一个节点在集合U中,一个不在,选出最小的e(u,v)
        将e(u,v)加入T,v加入U中
    5.返回这棵树
        

    可类比迪杰斯特拉算法,用一个数组标记节点是否属于T。每次从未标记的节点中选出d值最小的,把它的标记(新加入T),同时扫描所有边出边,更新另一个端点的d值,最后,最小生成树的权值总的和就是d[1]+d[2]+····+d[n]

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. using namespace std;
    17. typedef long long LL;
    18. const int N = 500 + 5, M = 1e5 + 5;
    19. int n, m;
    20. int G[N][N], d[N], vis[N];
    21. int prim() {
    22. memset(d, 0x3f3f3f, sizeof(d));//点到生成树的最小距离
    23. int ret = 0;
    24. for (int i = 0; i < n; i++) {
    25. int x = -1;
    26. for (int j = 1; j <= n; j++) {
    27. //vis[j]==1表示点j在U中
    28. //x==-1表示可以任选一个点作为初始节点
    29. // d[x] > d[j]:选出最小的e(u,v)的v
    30. if (!vis[j] && (x == -1 || d[x] > d[j]))
    31. x = j;
    32. }
    33. //当i!=0即上面的循环选出来的不是第一个点的时候,下面的循环已经更新过d数组的时候,d[x]==0x3f3f3f3f
    34. if (i && d[x] == 0x3f3f3f3f)
    35. return 0;
    36. if (i)
    37. ret += d[x];
    38. //更新e(u,v),用x更新所有点到这棵树的最小距离
    39. for (int j = 1; j <= n; j++) {
    40. if (d[j] > G[x][j])
    41. d[j] = G[x][j];
    42. }
    43. vis[x] = 1;
    44. }
    45. return ret;
    46. }
    47. int main() {
    48. scanf("%d%d", &n, &m);
    49. memset(G, 0x3f3f3f3f, sizeof(G));
    50. for (int i = 1, a, b, w; i <= m; i++) {
    51. scanf("%d%d%d", &a, &b, &w);
    52. G[a][b] = min(G[a][b], w);
    53. G[b][a] = min(G[b][a], w);
    54. }
    55. int ans = prim();
    56. if (ans == 0)
    57. cout << "impossible" << endl;
    58. else
    59. cout << ans << endl;
    60. return 0;
    61. }

  • 相关阅读:
    【C# 基础精讲】类和对象的概念
    【LeetCode】592. 分数加减运算
    QtC++与QTableView详解
    刷爆 LeetCode 周赛 339,贪心 / 排序 / 拓扑排序 / 平衡二叉树
    54、WEB攻防——通用漏洞&跨域CORS资源&JSONP回调&域名接管劫持
    Unity 从0开始编写一个技能编辑器_01_分析需求
    数字化经济的前沿:深入了解 Web3 的商业模式
    Q_PROPERTY 中notify关键词使用
    VJ第一周个人训练赛
    Halcon (0):C# 联合Halcon方式简介和就业市场说明
  • 原文地址:https://blog.csdn.net/Landing_on_Mars/article/details/132856756