由Prim学会Dijkstra

最近在准备机试,刷一些基础题。做到图论的时候把之前学的Prim和Dijkstra复习一下。虽然一个是最小生成树,一个是最短路,但算法思路非常像,除了扩展点时的条件不同,其他过程几乎一样。这里就用两道洛谷普及/提高-难度的题进行对比记忆。

Prim算法及其堆优化在我很久之前的博客写过,如果不会可以去学习Prim及其堆优化本文只对Prim和Dijkstra进行对比。

 

先贴题和AC代码,对比在后面,不需看题的直接跳到最后。

首先是最小生成树的题

P1194 买礼物

AC源码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
#define INF 1<<15
#define white 0
#define black 1
using namespace std;

int a,b;
int graph[505][505];
int color[505];
int dis[505];

struct node{
    int num;
    int len;
    node(){}
    node(int a,int b):num(a),len(b){}
};

struct comp{
    bool operator()(node a,node b){
        return a.len>b.len;
    }
};

void prim(int x){
    priority_queue<node,vector<node>,comp> q;
    //dis[x]=0;
    q.push(node(x,a));
    while(!q.empty()){
        node temp=q.top();
        q.pop();
        dis[temp.num]=min(temp.len,min(dis[temp.num],a));
        color[temp.num]=black;
        for(int i=1;i<=b;i++){
            if(color[i]==white){
                if(graph[temp.num][i]>=dis[i])continue;
                q.push({i,graph[temp.num][i]});
            }
        }
    }
}


int main(){
    cin>>a>>b;
    int temp;
    for(int i=1;i<=b;i++){
        for(int j=1;j<=b;j++){
            cin>>temp;
            if (temp==0)graph[i][j]=graph[j][i]=a;
            else graph[i][j]=graph[j][i]=temp;
        }
    }

    for(int i=1;i<=b;i++)dis[i]=INF;
    prim(1);
    int res=0;
    for(int i=1;i<=b;i++)res+=dis[i];
    cout<<res;
    return 0;
}

然后是最短路的题

P4779 单源最短路经

AC源码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
#define white false
#define black true
using namespace std;

struct path{
    int des;
    long long int len;
    path(){}
    path(int a,long long int b):des(a),len(b){}
};
vector<path> graph[100005];
long long int dis[100005];
bool color[100005];
int n,m,s;
struct comp{
    bool operator()(path a,path b){
        return a.len>b.len;
    }
};

void dijkstra(int x){
    priority_queue<path,vector<path>,comp> q;
    q.push({x,0});
    vector<path>::iterator it;
    while(!q.empty()){
        path temp=q.top();
        q.pop();
        if(color[temp.des])continue;
        color[temp.des]=black;
        dis[temp.des]=min(temp.len,dis[temp.des]);
        for(it=graph[temp.des].begin();it!=graph[temp.des].end();it++){
            if(color[it->des])continue;
            if(dis[temp.des]+it->len>=dis[it->des])continue;
            q.push({it->des,dis[temp.des]+it->len});
        }
    }

}

int main(){
    cin>>n>>m>>s;
    int u,v,w;
    for(int i=0;i<m;i++){
        cin>>u>>v>>w;
        graph[u].push_back({v,w});
    }
    memset(dis,127,sizeof(dis));
    dijkstra(s);
    for(int i=1;i<=n;i++){
        cout<<dis[i]<<' ';
    }
    return 0;
}

那么,我们将两道题的算法部分单独拉出来对比:

//Prim:
void prim(int x){
    priority_queue<node,vector<node>,comp> q;
    //dis[x]=0;
    q.push(node(x,a));
    while(!q.empty()){
        node temp=q.top();
        q.pop();
        dis[temp.num]=min(temp.len,min(dis[temp.num],a));
        color[temp.num]=black;
        for(int i=1;i<=b;i++){
            if(color[i]==white){
                if(graph[temp.num][i]>=dis[i])continue;
                q.push({i,graph[temp.num][i]});
            }
        }
    }
}

//Dijkstra
void dijkstra(int x){
    priority_queue<path,vector<path>,comp> q;
    q.push({x,0});
    vector<path>::iterator it;
    while(!q.empty()){
        path temp=q.top();
        q.pop();
        if(color[temp.des])continue;//最优性剪枝
        color[temp.des]=black;
        dis[temp.des]=min(temp.len,dis[temp.des]);
        for(it=graph[temp.des].begin();it!=graph[temp.des].end();it++){
            if(color[it->des])continue;
            if(dis[temp.des]+it->len>=dis[it->des])continue;//最优性剪枝
            q.push({it->des,dis[temp.des]+it->len});
        }
    }

}

我们可以看到,两段代码非常相像,都是从点x进行扩展,并使用了堆优化

除去剪枝部分,两段代码最大的不同在于扩展代码:

Prim:q.push({i,graph[temp.num][i]});

Dijkstra:q.push({it->des,dis[temp.des]+it->len});

因为Prim解决的问题是最小生成树,那么在扩展时只需考虑被扩展点和当前点(即生成树)的距离即可。插入优先队列后,每次取出的是当前队列中距离当前生成树最近的点,直接将该点连入生成树。

而Dijkstra解决的是图中所有点距离起点x的最短距离,那么在扩展时,不仅仅要考虑当前点与被扩展点之间的距离(it->len),还要考虑当前点与起点x的距离(dis[temp.des]),两者相加才是被扩展点距离起点x的距离(dis[temp.des]+it->len)。这样,在插入优先队列后,每次取出的点都是当前队列中距离起点x最近的点,取出该点后更新距离即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值