prim算法求最小生成树------Acwing858

地址:

描述:

思想:

流程:

区别:

令我困惑的点:

代码:

prim算法

与之对比的Dijkstra算法


地址:

https://www.acwing.com/problem/content/860/

很好的题解有输出路径的方式:

https://www.acwing.com/solution/content/38312/

描述:

思想:

流程:

S:当前已经在联通块中的所有点的集合
1. dist[i] = inf
2. for n 次
    t<-S外离S最近的点
    利用t更新S外点到S的距离
    st[t] = true
n次迭代之后所有点都已加入到S中

区别:

prim算法其实和Dijkstra算法很类似,最核心的区别在于:

Dijkstra算法是更新到起始点的距离,Prim是更新到集合S的距离

还有一个很重要的区别就是dist[]数组含义不一样

dijkstra算法:

if(dist[j]>dist[t]+g[t][j]) dist[j]=dist[t]+g[t][j];

 prim算法:

if(dist[j]>g[t][j]) dist[j]=g[t][j];

 至于为什么这是因为:dist[N]数组的含义不一样

在dijkstra算法中dist[]存储的是节点到起点的距离

而在prim算法里dist[]存储的是节点到已经构建好的生成树集合的最短距离

令我困惑的点:

for(int j=1;j<n;j++){
if(dist[j]>g[t][j]) dist[j]=g[t][j];}

 这句话的涵义是为了更新生成树外的点到生成树的距离

按道理来说dist[j]应该与(j节点到生成树中的每一个节点的距离)都进行一次对比为什么这里只是让dist[j]和g[t][j](t节点到j节点的距离)做比较呢?不会产生少比较然后导致更新不准确的情况吗?

其实这里我们完全不用担心,在自己过一遍流程后就会发现

 

代码:

prim算法

#include <iostream>
#include <cstring>
using namespace std;
const int N=510;
#define INF 0x3f3f3f3f
int n,m;
int g[N][N];
//dist[]存放某一节点到已经构建好的最小生成树集合的最短距离
int dist[N];
bool stu[N];
int prim(){
    dist[1]=0;
    int res=0;//是最小生成树的树边权重之和
    for(int i=0;i<n;i++){
        int t=-1;
        //找到与集合最近的点
        for(int j=1;j<=n;j++){
            if(!stu[j]&&(t==-1||dist[t]>dist[j])){
                t=j;
            }//if
        }//for(j)
        if(dist[t]==INF) return INF;
        else res+=dist[t];
        stu[t]=true;
        //更新生成树外的点到生成树的距离
        for(int j=1;j<=n;j++){
            //dist[j]=min(dist[j],g[t][j]);
            //dist[j]存储j节点到已经构建的最小生成树集合的最小距离
            //g[t][j]存储的是t节点到j节点的联通边的距离
            if(dist[j]>g[t][j]) dist[j]=g[t][j];
        }
    }//for(i)
    return res;
}
int main(){
    cin>>n>>m;
    memset(g,0x3f,sizeof g);
    memset(dist,0x3f,sizeof dist);
    for(int i=0;i<m;i++){
        int a,b,c;
        cin>>a>>b>>c;
        //have重边,且是无向图
        g[a][b]=g[b][a]=min(g[a][b],c);
    }
    int t=prim();
    if(t==INF)  cout<<"impossible";
    else cout<<t;
    return 0;
}

与之对比的Dijkstra算法

#include <iostream>
#include <cstring>
using namespace std;
const int N=510;
#define INF 0x3f3f3f3f
//用来存放节点间距离
int g[N][N];
//确定好与起点最短距离的节点
int stu[N];
//节点与起点之间距离
int dist[N];
int n,m;
int Dijkstra(){
    //起点与起点的距离为0
    dist[1]=0;
    //迭代n次,每次可以确定一个点到起点的最短路
    for(int i=0;i<n;i++){
        //t的作用判断有没有更新过
        int t=-1;
    //从1~n号节点中找,不在s集合,并且
    //没有更新过(t==-1),则进行更新, 或者发现更短的路径(dist[t]>dist[j]),则进行更新
        for(int j=1;j<=n;j++){
           if(!stu[j]&&(t==-1||dist[t]>dist[j])) {
               t=j;
           }//if
        }//for(j)
        stu[t]=true;
//找到了距离最小的点t,并用最小的点t去更新1~n号节点到起点的距离
//这里可能有同学要问j如果从1开始的话 会不会影响之前已经确定的点的最小距离
//但其实是不会 因为按照我们的Dijkstra算法的操作顺序 
//先确定最短距离的点的距离已经比后确定的要小 所以不会影响
//当然你也可以在循环判断条件里加上if(!st[i])
//这里j从1开始只是为了代码的简洁
        for(int j=1;j<=n;j++){
            dist[j]=min(dist[j],dist[t]+g[t][j]);
        }//for(j)
    }//for(i)
    //说明没有出路
    if(dist[n]==0x3f3f3f3f) return -1;
    else return dist[n];
}
int main(){
    cin>>n>>m;
    //初始化距离
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(i==j) g[i][j]=0;
            else g[i][j]=INF;
        }
    }
    //初始化dist[N]为无穷大
    memset(dist,0x3f,sizeof dist);
    for(int i=0;i<m;i++){
        //m条边,但有重边,所以当节点间有重边时,取边长最小的一条边
        int a,b,c;
        cin>>a>>b>>c;
        //取边长最短的一条边
        g[a][b]=min(g[a][b],c);
    }
    cout<<Dijkstra();
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值