【贪心】畅通工程系列总结-kruskal vs Prim

本文详细介绍了Kruskal和Prim两种求最小生成树的贪心算法,阐述了它们的适用场景:Kruskal适合稀疏图,Prim适合稠密图。通过代码示例,展示了如何使用这两种算法解决实际问题。

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

两种算法kruskal&Prim

这两种算法都是求最小生成树的贪心算法,但是出发角度不一样。kruskal算法是从边出发,将边按权值从小到大排序,然后遍历选边;Prim算法是从顶点的角度出发,在V-U中找离U最近的顶点。这就决定了这两种算法的适用范围,kruskal适用于点多边少的情况,适用于稀疏图;Prim算法适用于边多点少的情况,适用于稠密图。

一点想法

刚开始是在集合论图论中学的两种算法,当时还觉得不好用程序实现,直到后来在算法课上讲,懂了之后确实有一种恍然大悟的感觉。通过对畅通工程系列的整理和总结,我发现对于算法的理解是非常非常重要的,一旦你明白了这个算法的原理,就会很容易明白它的实现过程,或者说很容易用程序把它实现。

kruskal&Prim板子题

HDU1863-kruskal

#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=105;

struct road
{
    int b;//起点
    int e;//终点
    int v;//成本
} a[maxn*maxn/2];

int root[maxn];
int n,m;//道路数,村庄数
int ans;//最低成本
int cnt;//要修建的道路数目

void init()
{
    for(int i=0; i<maxn; ++i)
        root[i]=i;
    ans=0;
    cnt=0;
}

bool sort1(road r1,road r2)//按照成本从低到高排序
{
    return r1.v<r2.v;
}

int find_(int x)
{
    if(x==root[x])
        return x;
    else
    {
        root[x]=find_(root[x]);
        return root[x];
    }
}

void kruskal()
{
    init();
    sort(a+1,a+n+1,sort1);
    for(int i=1; i<=n; ++i)
    {
        int fb,fe;//记录两顶点的根结点
        fb=find_(a[i].b);
        fe=find_(a[i].e);
        if(fb!=fe)
        {
            if(fb<fe)
                root[fe]=fb;
            else
                root[fb]=fe;
            ans+=a[i].v;
            cnt++;
            if(cnt==m-1)
                break;
        }
    }
}

int main()
{
    while(cin>>n>>m&&n)
    {
        int i;
        for(i=1; i<=n; ++i)
            cin>>a[i].b>>a[i].e>>a[i].v;
        kruskal();
        if(cnt==m-1)
            cout<<ans<<endl;
        else
            cout<<"?"<<endl;
    }
    return 0;
}

HDU1233-Prim

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=105;
const int INF=1<<29;

int n,m;//顶点数,边数
int closest[maxn];//V-U中离U最近的顶点
int lowcost[maxn];//V-U中顶点到U的最小边权值
int vis[maxn];//是否在U中
int map_[maxn][maxn];
int ans;//最低成本

void init()
{
    for(int i=1; i<=n; ++i)
    {
        closest[i]=1;
        lowcost[i]=map_[i][1];
    }
    memset(vis,0,sizeof(vis));
    ans=0;
    vis[1]=1;
    lowcost[1]=0;
}

void Prim()
{
    init();
    int i,j,k,min_num;
    for(i=1; i<=n; ++i)
    {
        min_num=INF;
        k=0;
        for(j=1; j<=n; ++j)//找到V-U中离U最近的顶点
            if(!vis[j]&&lowcost[j]<min_num)
            {
                k=j;
                min_num=lowcost[j];
            }
        if(k==0)//V-U为空说明算法结束
            break;
        vis[k]=1;
        for(j=1; j<=n; ++j)//更新lowcost[]和closest[]
            if(!vis[j]&&map_[j][k]<lowcost[j])
            {
                lowcost[j]=map_[j][k];
                closest[j]=k;
            }
    }
}

int main()
{
    int i,j,a,b,v;
    while(scanf("%d",&n)==1&&n)
    {
        m=n*(n-1)/2;
        memset(map_,0,sizeof(map_));
        for(i=0; i<m; ++i)
        {
            scanf("%d%d%d",&a,&b,&v);
            map_[a][b]=v;
            map_[b][a]=v;
        }
        Prim();
        for(i=1; i<=n; ++i)
            ans+=lowcost[i];
        printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值