最小生成树总结(Prim,Kruskal)

本文深入探讨了最小生成树的概念及其两种主要算法:Kruskal和Prim。通过详细解释每种算法的工作原理,包括排序、并查集和迭代过程,帮助读者理解如何构造一个权重最小的连通图。

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

最小生成树就是用最少的边让图连通
Kruskal:
首先按照边权进行从小到大进行排序,每次从剩余的边中选择权值最小且边的两个顶点不在同一个集合内的边(就是不会产生回路的边),加入生成树中,直到加入了n-1条边。
代码:

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=105;//N的数值和边数有关
struct edge
{
    int u;
    int v;
    int w;
}e[N];
int n,m;
int f[N]={0},sum=0,cnt=0;//并查集用的变量
void quicksort(int left,int right)
{
    int i,j;
    struct edge t;
    if(left>right)
        return;

    i=left;
    j=right;
    while(i!=j)
    {
        while(e[j].w>=e[left].w && i<j)
        j--;
        while(e[i].w<=e[left].w && i<j)
        i++;

        if(i<j)
        {
            t=e[i];
            e[i]=e[j];
            e[j]=t;
        }
    }
        t=e[left];
        e[left]=e[i];
        e[i]=t;

        quicksort(left,i-1);
        quicksort(i+1,right);
        return;
}
bool comp(struct edge a,struct edge b)//sort中的比较函数
{
    return a.w < b.w;
}
//并查集找祖先
int getf(int v)
{
    if(f[v]==v)
        return v;
    else
    {
        f[v]=getf(f[v]);
        return f[v];
    }
}
//并查集合并子集
int merge1(int v,int u)
{
    int t1,t2;
    t1=getf(v);
    t2=getf(u);
    if(t1!=t2) //不在生成树返回1,并加入生成树
    {
        f[t2]=t1;
        return 1;
    }
    return 0;
}


int main()
{
    int i;
    scanf("%d %d",&n,&m);
    cnt=0,sum=0;
    for(i=1; i<=m; i++)
        scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w);
    quicksort(1,m);//快速排序
   //sort(e+1,e+m+1,comp);//算法的快排

    for(i=1; i<=n; i++)
    {
        f[i]=i;
    }

    for(i=1; i<=m; i++)
    {
        if( merge1(e[i].u,e[i].v) )
        {
            cnt++;
            sum=sum+e[i].w;
        }
        if(cnt == n-1)
            break;
    }

    printf("%d",sum);

    return 0;
}
/*
6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
1 2 1
3 4 9
1 3 2

ans:19
*/

Prim : 图中顶点分两类,树顶点(已加入生成树),非树顶点(未加入生成树)。首先选择任意顶点加入生成树,然后找出一条边加入生成树,这需要枚举每个树顶点到每个非树顶点所以的边,然后找到最短边加入最小生成树,重复n-1,直到将所有的顶点都加入到生成树中。
dis[N] 数组用来存放生成树到个各点的距离。

#include<cstdio>
#include<cstring>
const int N=105;
int main()
{
    int n,m,i,j,k,minn,t1,t2,t3;
    int e[N][N],dis[N],book[N];
    int inf=0x3f3f3f;
    int cnt,sum;

    scanf("%d %d",&n,&m);
    cnt=0,sum=0;
    //图初始化
    for(i=1; i<=n; i++)
    {
        for(j=1; j<=n; j++)
        {
            if(i==j) e[i][j]=0;
            else e[i][j]=inf;
        }
    }

    for(i=1; i<=m; i++)
    {
        scanf("%d %d %d",&t1,&t2,&t3);
        e[t1][t2]=t3;
        e[t2][t1]=t3;
    }
    //dis,book数组初始化
    for(i=1; i<=n; i++)
        dis[i]=e[1][i];
    memset(book,0,sizeof(book));
    book[1]=1;
    cnt++;
    while(cnt<n)
    {
        minn=inf;
        for(i=1; i<=n; i++)
        {
            if(book[i]==0 && dis[i]<minn)
            {
                minn=dis[i];
                j=i;
            }

        }
        book[j]=1; cnt++; sum+=dis[j];
        for(k=1; k<=n; k++)
        {
            if(book[k]==0 && dis[k]>e[j][k])
                dis[k]=e[j][k];
        }
    }

    printf("%d",sum);


    return 0;
}
/*
6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
1 2 1
3 4 9
1 3 2
*/

最小生成树题目

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值