[蓝桥杯 2022 国 B] 出差(最短路问题,dijkstra+优先队列)

题目描述:

输入格式:

输出格式:

输入样例:

4 4
5 7 3 4
1 2 4
1 3 5
2 4 3
3 4 5

输出样例:

13
#include<bits/stdc++.h>
using namespace std;
const int N=1010,M=10010;
struct node{
    int x,y;
    bool operator<(const node&x)const{//这个用于去让优先队列,根据y值进行排列
        return x.y<y;
    }
};
int n,m;
vector<node>a[N];//vector容器用来存图
bool st[N];
int res[N],s[N];//res用于存放起点到达每个点的最短路答案
priority_queue<node>q;//优先队列,存node类型,根据y值优先将y最小的值弹出队列
void dijkstra()
{
    memset(res,0x3f,sizeof res);//先将每个答案初始化很大,用于每次更新答案
    q.push({1,0});//将起点和此时的路径时间入队
    res[1]=0;//将起点的答案更新为0
    while(q.size())//队列不为空便一直循环
    {
        auto t=q.top();//得到队列的第一个便是路径也就是时间最小的那个
        q.pop();//将队头弹出去
        int ver=t.x;//此时的起点
        if(st[ver]) continue;//如果这个点已经更新过了便直接跳过,防止走回路
        st[ver]=true;
        for(auto &i:a[ver])//遍历此时这个点能够到达的每一个点
        {
            int x=i.x,y=i.y;
            if(res[x]>res[ver]+y+s[ver])//如果他能到达的点的答案大于这个点到他的答案那么就更新
            {
                res[x]=res[ver]+y+s[ver];//更新答案
                q.push({x,res[x]});//同时将走到的这个点给入队
            }
        }
    }
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>s[i];
    s[1]=0;
    while(m--)
    {
        int x,y,z;
        cin>>x>>y>>z;
        a[x].push_back({y,z});//用vector存图
        a[y].push_back({x,z});//由于是无向边所以记得一个边的两个点都要当一次起点
    }
    dijkstra();
    cout<<res[n];
    return 0;
}

题解:

这道题仔细都题目就会发现也算是一道很典型的最短路径问题,只不过多了一个条件就是题目中所叙述的多了一个隔离时间,所以在最短路的判断时加上隔离时间即可,所以只能说是换汤不换药。

像这种典型的最短路问题,而且不带负权边的题,直接dijkstra算法加上一个堆优化直接Ac了

其实也算是一个板子题,

我这里存图的时候用的vector存图,vector容易本来就可以看成一个数组,现在又给他开了一个node结构体类型的数组,而在每个下标对应的值也算是一个数组,变相的来说,就是一个node类型的二维结构体数组,而每个下标就相当于每条边的或者说是每条路的起始点,数组里面存的便是这个点能够到达点,以及这两个点之间的边权,(实在不理解的话,就给当作一个板子记下来就行了)。

然后这个算法用堆优化用到了优先队列,为了方便排序我便直接在结构体的写了一个bool类型的判断,正好用于优先队列的排序,不明白的可以先具体了解一下优先队列priority_queue。

dijkstra算法本质意义就是从起点开始,每次具体更新一个点,(某种意义上来讲的话其实有那么一点点像BFS一层层往外面扩散的样子),而且每次更新的点就都是这个点能到达的最短路,因为每次都会把下一次走到的点给放进优先队列,而优先队列会根据上一次走到这个点的路径优先将路径最小值给弹出队列,所以每次更新的路径就是最短路,起点能走到各个点的最短路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值