Poj No.3255 Roadblocks(次短路径)

文章目录

  • 前言
  • Dijkstra核心思想
  • 代码详解、
  • 附完整AC代码
  • 总结


前言

题目链接:
洛谷

大一小白初学Dikstra算法,在勉强弄清楚最短路径模版题([模版] (https://www.luogu.com.cn/problem/P4779))后,尝试了一下稍微进阶一点的题,脑子彻底紊乱了,好在在逐步摸索下,逐渐搞清楚了这道题。
我真是猪脑

Dijkstra核心思想

Dijkstra算法:用于解决 单源最短路径问题。
其核心的两点为

(1).找到最短距离已经确定的顶点,从它出发更新相邻顶点的最短距离(注意:是相邻顶点距离,可能包含多个点本彩笔就是忽略了这点而陷入了迷茫
(2).此后就不再需要关心1中的“最短距离已经确定的顶点”。

(1)(2)中提到的“最短距离已经确定的顶点”如何得到是本题的关键。在最开始时,只有起点的最短距离是确定的,而在尚未使用的顶点中,距离distant[i]最小的顶点就是最短距离已经确定的顶点。
PS:这是因为在本算法可行的条件中,不存在负边,所以distant[i]不会在之后的更新中变小。

思路来源《挑战程序设计竞赛》 基本都是我抄来的

代码详解、

进入代码:

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn=5e5+5 ;
const int maxm=1e5+5;
struct edge{  //构建结构体  to-顶点,这里是道路终点农场  cost-边权值,这里即距离
    int to,cost;
};
typedef pair<int ,int > P;  //first 是最短距离,second是顶点编号
int n,m;  //没什么好说的,n个顶点,m条边。
int distant1[maxn];//记录最短距离
int distant2[maxn];//记录次短距离

vector<edge> g[maxm];//图的邻接表表示

其中 pair是c++的模板类,用于存储一对值。它包含两个公共成员变量 first 和 second,分别表示第一个值和第二个值。
pair 在很多情况下非常有用,例如在算法中返回多个值、构建映射等
``
接下来是主函数

int main()             //求次短路径长度
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;++i){
        int u,v,c;
        scanf("%d%d%d",&u,&v,&c);
        g[u].push_back({v,c});
        g[v].push_back({u,c});   //根据题目背景可知本题是无向图,所以构建双向道路
    }    

这里即简单的输入数据

以下为本题代码实现过程以及主要的批注

    priority_queue<P,vector<P>,greater<P> >que;
    //构建优先队列用于寻找最短路径
    //元素类型为之前typedef后的pair ——— P
    //用vector作为底层容器,采用greater作为比较器。
    //greater是STL中的函数对象(function object),用于提供元素的比较规则,
    //这里优先队列会将元素按照从小到大的顺序进行排序。

    fill(distant1+1,distant1+n+1,INF);  // 初始化最短距离为无穷大
    fill(distant2+1,distant2+n+1,INF);  // 初始化次短距离为无穷大

    distant1[1]=0;     // 起始点到自身的距离为0
    que.push(P(0,1));    // 将起始点加入优先队列
    
    while(!que.empty()){
        P p=que.top();  
        que.pop();    //取出队列的队首
        int v=p.second;   //  v 获取顶点编号
        int d=p.first;   //   d  获取当前最短距离
        if(distant2[v]<d){ //若当前顶点的次短距离比最短距离还低,进入下一轮。
            continue;
        }
        
        for(unsigned long long int i=0;i<g[v].size();++i){   遍历
            edge &e=g[v][i]; 
            //这里使用了引用赋值
            //g[v][i]表示图中从顶点 v 出发的第 i 条边,
            //而 edge &e 则是将该边赋值给引用变量 e。


            int d2=d+e.cost;//暂时存储下一次的距离,遍历得到最短距离

            //首先,判断 distant1[e.to] 是否大于 d2。
            //如果是,则说明通过顶点 v 到达顶点 e.to 的路径更短,
            //需要更新最短距离和将该顶点加入优先队列。
            if(distant1[e.to]>d2){     //更新最短距离
                swap(distant1[e.to],d2); 
                //这里用swap是怕丢失原先存储在 distant1[e.to]的数据
                que.push(P(distant1[e.to],e.to));
            }


            //接下来,判断distant2[e.to]是否大于d2且distant1[e.to]小于d2。
            //如果是,则说明通过顶点v到达顶点e.to的路径
            //虽然不是最短路径,但是可以更新为次短路径
            if(distant2[e.to]>d2 && distant1[e.to]<d2){
                distant2[e.to]=d2;
                que.push(P(distant2[e.to],e.to));
            }
        }
    }
    printf("%d",distant2[n]);
    //最后的结果储存在distant2[n]里,输出。
    return 0;
}
---

附完整AC代码

#include <bits/stdc++.h>
using namespace std;


const int INF = 0x3f3f3f3f;
const int maxn=5e5+5 ;
const int maxm=1e5+5;
struct edge{
    int to,cost;
};
typedef pair<int ,int > P;  //first 是最短距离,second是顶点编号
int n,m;
int distant1[maxn];
int distant2[maxn];
vector<edge> g[maxm];
int main()             //求次短路径长度
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;++i){
        int u,v,c;
        scanf("%d%d%d",&u,&v,&c);
        g[u].push_back({v,c});
        g[v].push_back({u,c});
    }
    priority_queue<P,vector<P>,greater<P> >que;
    fill(distant1+1,distant1+n+1,INF);
    fill(distant2+1,distant2+n+1,INF);
    distant1[1]=0;
    que.push(P(0,1));
    while(!que.empty()){
        P p=que.top();
        que.pop();
        int v=p.second;//顶点编号
        int d=p.first;//最短距离
        if(distant2[v]<d){ //若次短距离比最短距离还低,继续
            continue;
        }
        for(unsigned int i=0;i<g[v].size();++i){
            edge &e=g[v][i];
            int d2=d+e.cost;
            if(distant1[e.to]>d2){     
                swap(distant1[e.to],d2);
                que.push(P(distant1[e.to],e.to));
            }
            if(distant2[e.to]>d2 && distant1[e.to]<d2){
                distant2[e.to]=d2;
                que.push(P(distant2[e.to],e.to));
            }
        }
    }
    printf("%d",distant2[n]);
    return 0;
}

总结

本题巧妙地利用Dijkstra算法的思路,在其基本算法思路上稍加修改,相当于进行了两次Dijkstra即可得到最后的答案。

  • 25
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值