题目描述
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;
}