牛客PAT甲级练习题 1009 Travel Plan (30)

题意

考察Dijkstra算法,双重边权。

思路

寻找最优路径并记录(pre),最后后序遍历输出路径。

#pragma GCC optimize(2)
#include"bits/stdc++.h"
using namespace std;

const int maxn = 510;
int G[maxn][maxn];      int G2[maxn][maxn];
int dis[maxn];          int dis2[maxn];
int vis[maxn];

struct Node{
    bool operator()(int a,int b){
        return dis[a] >= dis[b];
    }
};

int n,m,s,d;
int pre[maxn];
void diskj(int startId){
    fill(dis,dis+maxn,INT32_MAX);   dis[startId] = 0;
    fill(dis2,dis2+maxn,INT32_MAX); dis2[startId] = 0;
    priority_queue<int,vector<int>,Node> q;
    q.push(startId);
    for (int i = 0; i < n; ++i) {
        int id;
        while (true){
            if (q.empty()) {
                return;
            } else if (vis[q.top()]) {
                q.pop();
                continue;
            }
            id = q.top(); q.pop(); vis[id] = 1;
            break;
        }
        for (int j = 0; j < n; ++j) {
            if (vis[j] || G[id][j] == INT32_MAX)
                continue;
            int ec = dis[id] + G[j][id],ec2 = dis2[id] + G2[j][id];
            if (ec < dis[j]){
                dis[j] = ec;  dis2[j] = ec2;
                q.push(j); pre[j] = id;
            } else if (ec == dis[j] && ec2 < dis2[j]){
                dis2[j] = ec2;
                q.push(j); pre[j] = id;
            }
        }
    }
}
//后序遍历输出从 startId 到 id 的路径
void show(int id,int startId){
    if (id == startId) {
        printf("%d ",startId);
        return;
    }
    show(pre[id],startId);
    printf("%d ",id);
}
int main(){
    fill(G[0],G[0]+maxn*maxn,INT32_MAX); fill(G2[0],G2[0]+maxn*maxn,INT32_MAX);
    //freopen("input.txt","r",stdin);
    cin >> n >> m >> s >> d;
    for (int i = 0; i < m; ++i) {
        int id1,id2,c1,c2; scanf("%d%d%d%d",&id1,&id2,&c1,&c2);
        G[id1][id2] = G[id2][id1] = c1; G2[id1][id2] = G2[id2][id1] = c2;
    }
    diskj(s);
    show(d,s);
    printf("%d %d\n",dis[d],dis2[d]);
}

input

4 5 0 3 0 1 1 20 1 3 2 30 0 3 4 10 0 2 2 20 2 3 1 20

ouput

0 2 3 3 40
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值