Kruskal/Prim最小生成树

本文介绍了最小生成树的概念,包括树的定义、性质和最小边的代价。详细讲解了Kruskal算法,它利用贪心思想与并查集避免形成环,以及Prim算法,该算法同样基于贪心策略,通过“蓝白点”思想逐步构建最小生成树。文中还提到了Prim算法与Dijkstra和Bellman-Ford算法的相似性,并给出了完整的程序实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最小生成树

定义

连通,但不成环

  • 最小

边的代价和最小

规律

  • 举例

    以四个点为例,共需三条线即可。

    1. 同类共四种(任意去掉其中一条线)
    2. 同类共四种
    3. 同类共四种(任意去掉其中一条线)
    4. 同类共四种(任意去掉其中一条线)
  • 总结

    n个点生成树需要(n-1)条线来连通。

克鲁斯卡尔 Kruskal

贪心思想+并查集(检查是否成环)

  1. 用边权按从小到大排序
  2. 初始化并查集
  3. 循环加边,检查是否成环 (n-1条

普莱姆 Prim

运用了,贪心思想

贪心:

一种结果很准确,但是占的空间很大很大。
所以我们这次要用这种很好的方法来做。

Prim

Prim算法跟Dij和Bellman-算法一样。

也是使用了”蓝白点”的思想

Prim算法每次循环都要将一个蓝点u变为一个白点,这样循环,min[u]里面的权还是最小的

  1. 初始化

    对于flag操作的问题:

memset(flag,true,sizeof flag);

解释:

把flag全部填为真(True)

对于f

for (int i=1;i<=n;++i) f[i]=0x7fffffff; f[1]=0;

注意哦,这里不能用memset,那样会卡爆!!

解释:

如果呢?到了
对于map

memset(map,0,sizeof map);

2.循环

for (int i=1;i<=n-1;++i){

    //1.在f中查找最小权值的编号(且flag==false) 
    int min1=0x7fffffff; 
    int v=-1;

    for (int j=1;j<=n;++j){

        if (flag[j] && min1>f[j]){

            min1=f[j];

            v=j;


        }

    }

    //2.标记v 
    flag[v]=false;

    //3.更新v发出的边 
    for (int j=1;j<=n;++j){

        if (flag[j] && map[v][j]!=0){

            if (map[v][j]<f[j]) f[j]=map[v][j];

        }

    }

} 

附上完整程序

//邻接矩阵 


#include <cstdio>
#include <cstring>

const int N=110;

int map[N][N],n,m,x,y,z,f[N];

bool flag[N];

int main(){

    freopen("prim.in","r",stdin);
    freopen("prim.out","w",stdout);

    scanf("%d%d",&n,&m);

    memset(map,0,sizeof map);

    for (int i=1;i<=m;++i){

        scanf("%d%d%d",&x,&y,&z);

        map[x][y]=z; map[y][x]=z;

    }

    memset(flag,true,sizeof flag); 

    for (int i=1;i<=n;++i) f[i]=0x7fffffff; f[1]=0; 

    for (int i=1;i<=n-1;++i){

        //1.在f中查找最小权值的编号(且flag==false) 
        int min1=0x7fffffff; 
        int v=-1;

        for (int j=1;j<=n;++j){

            if (flag[j] && min1>f[j]){

                min1=f[j];

                v=j;


            }
        //更新我的指令
        //

        }

        //2.标记v 
        flag[v]=false;

        //3.更新v发出的边 
        for (int j=1;j<=n;++j){

            if (flag[j] && map[v][j]!=0){

                if (map[v][j]<f[j]) f[j]=map[v][j];

            }

        }

    } 

    int ans=0;

    for (int i=1;i<=n;++i) ans+=f[i];

    printf("%d",ans);

    return 0;

} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值