首页 > 其他 > 详细

最小生成树 kruskal prim

时间:2019-07-06 23:01:09      阅读:95      评论:0      收藏:0      [点我收藏+]

差不多就要CCF考试了,弱鸡我还是挺慌的(好想上400分保研~),最近开始来逐渐巩固自己所储备的知识。

CCF的第四题往往是图论,今天就来回顾一下经典的最小生成树算法:Kruskal && Prim。

  • Kruskal:遍历边,边的累加生成树--适用于边较稀疏的情况。

  边用结构体数组存储,属性有:两个端点,权值。

  将所有边由小到大排序, 以最短的边为算法的起始。依次遍历剩下的边,结合并查集判断是否会形成强连通,不行成强连通的剩下边加入到树中。截止条件,边数 == 点数 - 1。

  个人容易出错的地方:

  1)并查集的Unite函数中,两个点的根节点应要通过FindRoot函数来查找,而不是直接用Root【】数组(数组存储的是父节点,单并不一定是祖宗节点),连通性是通过最祖宗的节点是否相连来判断的。

  2)遇到多组测试用例时,要记得将重复使用的量重新初始化。

代码(待):明天就写哈~

 

  • Prim:遍历点, 点的集合生成树--适用于边较密集的情况

  由于边较密集,用邻接矩阵table【】【】来存边,存边权时注意边的双向性

  用minCnt【】数组存所有点到树的距离,个人习惯以1为初始的树根st(哪个点都无所谓,因为所有点都要取到),即初始的minCnt为所有点到st点的距离table[st][index]。

  vis【】标记点进入树的情况。

  先初始化minCnt,标记我们的st点(初始的树),因为已经找到一个点了,所以之后是一个总点数 - 1次的循环,即 n - 1 次, 找到剩下的 n - 1个点。在这个大循环中,每次遍历剩下的点,找到到树距离最短的(用minLen存最短距离,minNode存最小的点的编号,桶排思想),标记入树,同时累加树的总权值。接着,由于树的扩张,我们需要更新剩下点到树的最小距离minCnt, 又是一个循环。总体上就是,一个大循环,内嵌两个小循环。

  个人容易出错的地方:

  1)这里各点到树的距离会随着树的生成不断变化,所以没有必要一开始sort排序,每次查找时用循环桶排就好。

  2)最初始的点就是初始的树,所以到树的距离为0,minCnt【st】 = 0。

  这里贴一道CCF的第四题(这是比较早的CCF题,所以不难,竟然只是个模板题~),顺便扇自己一巴掌--我做题时,一看以为是求单源最短路径,上来就敲spfa,结果浪费了时间。真正考试时要稳一点,在纸上大致模拟一遍思路看是否符合题意再开始写。

//minimum spanning tree 
//边较多,用prim
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
#define Inf 0x3f3f3f3f
#define ll long long
const int maxp = 1000 + 2, st = 1;
int table[maxp][maxp], minCnt[maxp]; // 到树的距离
bool vis[maxp];
int n, m, a, b, c, cntp;
ll sumw;

void Prim()
{
    for(int i=2;i<=n;++i){
        minCnt[i] = table[st][i];
    }
    minCnt[st] = 0;
    vis[st] = true;    //第一个节点入树

    for(int t=1; t < n; ++t){//找到剩下的n-1个节点
        int minNode = 0, minLen = Inf;
        for(int j = 1; j <= n; ++j){
            if(!vis[j] && minCnt[j] < minLen){
                minLen = minCnt[j];
                minNode = j;
            }
            else continue;
        }
        sumw += minLen; //生成的一支的权值
        vis[minNode] = true;
        for(int j = 1; j<= n; ++j){
            if(!vis[j]){//更新到树的距离
                minCnt[j] = min(minCnt[j], table[minNode][j]);
            }
        }
    }
}
inline int read(){
    char ch = getchar();
    int ans = 0;
    while(ch < 0 || ch > 9) ch = getchar();
    while(ch >= 0 && ch <= 9){
        ans = (ans << 3) + (ans << 1) + ch - 0;
        ch = getchar();
    }return ans;
}
int main()
{
    n = read(), m = read();
    memset(table, Inf, sizeof(table));
    while(m--){
        a = read(), b = read(), c = read();
        table[a][b] = table[b][a] = min(table[a][b], c);
    }
    Prim();
    printf("%lld\n", sumw);
    return 0;
}

 

最小生成树 kruskal prim

原文:https://www.cnblogs.com/GorgeousBankarian/p/11144382.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!