普里姆(prim)算法--求最小生成树

教学地址:

普里姆算法

算法核心:

(T集合包含生成树中的结点,V集合包含所有结点)

在连接T内顶点与V-T内顶点的边中选取权值最小的边(pu,u),将其作为MST(最小生成树)的边,并添加u至T中!

代码实现:

#include <bits/stdc++.h>

#define ll long long
using namespace std;

const int maxn=1000+10;
int n,ans,ecnt,m;
int head[maxn],vis[maxn];
int ma[maxn][maxn],d[maxn];

struct node
{
    int u,v,next;
} E[maxn];

bool flag=false;
void add(int u,int v)
{
    E[++ecnt].u=u;
    E[ecnt].v=v;
    E[ecnt].next=head[u];
    head[u]=ecnt;
}

void prim()
{
    memset(d,0x7f7f7f7f,sizeof(d));//注意初始化
    int u;
    d[1]=0;//以1为根节点
    for(int i=1; i<=n; i++) //最多遍历n次
    {
        u=0;//注意是0,不是1
        //找famous结点
        for(int j=1; j<=n; j++)
        {
            if(!vis[j]&&d[j]<d[u]){
                u=j;
            }
        }
        vis[u]=1;
        ans+=d[u];//最小生成树
        //更新d,是全图更新,而非famous扩展出去的那几个点
        for(int j=1; j<=n; j++)
        {
            if(!vis[j]&&ma[u][j]<d[j]&&ma[u][j]!=-1)
            {
                d[j]=ma[u][j];
            }
        }
    }
}


int main()
{

    cin>>n;

    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            cin>>ma[i][j];
        }
    }
    prim();
    cout<<ans;

    return 0;
}


链式前向星实现

#include <bits/stdc++.h>

#define ll long long
using namespace std;

const int maxn=4e5+10;
int n,ans,ecnt,m;
int head[maxn],vis[maxn];
int d[maxn];

struct node
{
    int u,v,w,next;
} E[maxn];

bool flag=false;
void add(int u,int v,int w)
{
    E[++ecnt].u=u;
    E[ecnt].v=v;
    E[ecnt].w=w;
    E[ecnt].next=head[u];
    head[u]=ecnt;
}

void prim()
{
    memset(d,0x7f7f7f7f,sizeof(d));//注意初始化
    int u;
    d[1]=0;//以1为根节点
    for(int i=1; i<=n; i++) //最多遍历n次
    {
        u=0;//注意是0,不是1
        //找famous结点
        for(int j=1; j<=n; j++)
        {
            if(!vis[j]&&d[j]<d[u]){
                u=j;
            }
        }
        vis[u]=1;
        ans+=d[u];//最小生成树
        //更新d,是全图更新,而非famous扩展出去的那几个点
        for(int i=head[u];i;i=E[i].next)
        {
            int v=E[i].v;
            if(!vis[v]&&E[i].w<d[v])d[v]=E[i].w;
        }
    }
}


int main()
{

    cin>>n>>m;
    for(int i=1; i<=m; i++)
    {
       int u,v,w;
       cin>>u>>v>>w;
       add(u,v,w);
       add(v,u,w);
    }
    prim();
    for(int i=1;i<=n;i++)
    {
        if(!vis[i]) {
            cout<<"有孤立点"<<endl;
            return 0;
        }
    }
    cout<<ans;

    return 0;
}


算法总结:

prim算法可以分为两个步骤
1、找到G-T集合中路径最小的点
2、更新数组d,注意是全图更新,而非只更新与白点相连的点

这两步相互依存,通过起点更新数组d,通过数组d,来找出新的起点!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值