1384-PIPI的飞行路线(优先队列优化的dijkstra解法)

题目描述
PIPI的世界有N个国家,PIPI现在想从1号国乘飞机飞往N号国,给出国家之间的往返航线以及单程机票费用。
现在PIPI获得了一张免费机票,用这张机票可以免费在指定的航线飞行一次。现在PIPI最少要花多少钱?
如果不存在从1号国到N号国的路线,输出“No way!”
输入
第一行两个整数,N,M,分别表示国家数以及航线数。(N<=10000,M<=200000)
接下来M行,每行三个整数u,v,c,分别表示航线连接的两个国家,以及单程机票费用。注意航线是可以往返的,也就是双向的。(c<=10000)
接下来一个整数k,表示免费机票可以使用的航线数。(k<=10000)
接下来k行,每行两个整数u,v,表示免费机票可乘坐的航线连接的两个国家。
输出
如果不存在从1号国到N号国的路线,输出“No way!”
否则一行输出一个整数,为使用免费机票的最小费用。
样例输入
4 3
1 2 1
1 3 2
2 4 3
1
3 4
样例输出
2

#include <bits/stdc++.h>
using namespace std;
int dis[2][10005],n,m;  ///dis[0][i]表示从1号节点到各点的最短路,dis[1][i]表示从n号节点到各点的最短路
struct edge{    ///定义边节点
    int to,w;   ///to 表示边节点的终端节点,w表示边结点的权值
};
struct node{
    int u,d;    ///表示从源点到u点走了d的距离
    bool operator<(const node &a)const{
        return a.d<d;
    }
};
priority_queue<node> q;
vector<edge> mp[10005];
void dij(bool a,int s){
    int i,j,v,w;
    for(int i=1;i<=n;i++) dis[a][i]=1e9;
    ///到自己为0
    dis[a][s]=0,q.push({s,0});
    while(q.size()){
        node now = q.top();q.pop();
        if(dis[a][now.u]<now.d) continue;   ///如果该节点的d大于dis保存的最小值,直接舍弃这个状态
        for(int i=0;i<mp[now.u].size();i++){///更新该节点到其他节点的最短距离
            v=mp[now.u][i].to,w=mp[now.u][i].w;	///获取连接的下个节点v以及边权w
            if(dis[a][v]>dis[a][now.u]+w) dis[a][v]=dis[a][now.u]+w,q.push({v,dis[a][v]});  ///满足条件更新dis数组并将v节点入队
        }
    }
}
int main(){
    int i,u,v,w,ans;
    scanf("%d%d",&n,&m);
    while(m--){
        scanf("%d%d%d",&u,&v,&w);
        mp[u].push_back({v,w});
        mp[v].push_back({u,w});
    }
    dij(0,1),dij(1,n),ans=dis[0][n]; ///1号节点和n号节点做两次dis,处理出dis数组,ans暂为不使用免费机票的最短距离
    int k;
    scanf("%d",&k);
    while(k--){
        scanf("%d%d",&u,&v);
        ans=min(ans,dis[0][u]+dis[1][v]);
        ans=min(ans,dis[1][u]+dis[0][v]);
    }
    if(ans==1e9) printf("No way!");
    else printf("%d\n",ans);
    return 0;
}

链式前向星存图解法如下

#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 5, M = 4e5 + 7;
int n,m;
typedef pair<int ,int > pii;

int h[N],e[M],ne[M],w[M],idx;
int st[2][N];
void add(int a,int b,int c){
    e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx ++;
}
int dis[2][10005];

void dij(int a,int s){

    idx = 0;									///因为要跑两次dijkstra故idx要初始化为0
    for(int i=1;i<=n;i++) dis[a][i] = 1e9;
    dis[a][s] = 0;
    priority_queue<pii,vector<pii>,greater<pii>> q;
    q.push({0,s});

    while(q.size()){
        auto t = q.top();q.pop();
        int ver = t.second, distance = t.first;
        
        if(st[a][ver]) continue;
        st[a][ver] = true;
        for(int i = h[ver];i != -1;i = ne[i]){
            int j = e[i];
            if(dis[a][j] > distance + w[i]){
                dis[a][j] = distance + w[i];
                q.push({dis[a][j],j});
            }
        }
    }
    
}
int main(){
    scanf("%d%d",&n,&m);
    
    memset(h,-1,sizeof h);					///因为是单组数据输入故只需要读入一次边 
    while(m --){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c),add(b,a,c);
    }
    
    int ans;
    dij(0,1) , dij(1,n) , ans = dis[0][n];  ///ans暂时为不用免费机票的最短距离
    
    int k;
    scanf("%d ",&k);
    while(k --){
        int u,v;
        scanf("%d%d",&u,&v);
        ans = min(ans,dis[0][u] + dis[1][v]);
        ans = min(ans,dis[0][v] + dis[1][u]);
    }
    if(ans == 1e9) puts("No way!");
    else printf("%d\n",ans);

    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值