题目描述
AliceAliceAlice和BobBobBob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司。该航空公司一共在nnn个城市设有业务,设这些城市分别标记为000到n−1n-1n−1,一共有mmm种航线,每种航线连接两个城市,并且航线有一定的价格。
AliceAliceAlice和BobBobBob现在要从一个城市沿着航线到达另一个城市,途中可以进行转机。航空公司对他们这次旅行也推出优惠,他们可以免费在最多kkk种航线上搭乘飞机。那么AliceAliceAlice和BobBobBob这次出行最少花费多少?
输入输出格式
输入格式:
数据的第一行有三个整数,nnn,mmm,kkk,分别表示城市数,航线数和免费乘坐次数。
第二行有两个整数,sss,ttt,分别表示他们出行的起点城市编号和终点城市编号。
接下来有m行,每行三个整数,aaa,bbb,ccc,表示存在一种航线,能从城市aaa到达城市bbb,或从城市bbb到达城市aaa,价格为ccc。
输出格式:
只有一行,包含一个整数,为最少花费。
输入输出样例
输入样例#1:
5 6 1
0 4
0 1 5
1 2 5
2 3 5
3 4 5
2 3 3
0 2 100
输出样例#1:
8
说明
对于30%的数据,2≤n≤502 \le n \le 502≤n≤50,1≤m≤3001 \le m \le 3001≤m≤300,k=0k=0k=0,
对于50%的数据,2≤n≤6002 \le n \le 6002≤n≤600,1≤m≤60001 \le m \le 60001≤m≤6000,0≤k≤10\le k \le 10≤k≤1;
对于100%的数据,2≤n≤100002 \le n \le 100002≤n≤10000,1≤m≤500001 \le m \le 500001≤m≤50000,0≤k≤100≤k≤100≤k≤10,
0≤c≤10000≤s,t<n0 \le c \le 10000≤s,t<n0≤c≤10000≤s,t<n,0≤a0≤a0≤a,b<nb<nb<n,a≠ba≠ba̸=b,0≤c≤10000≤c≤10000≤c≤1000
今上午考试考了这道题,数组开小了QAQQAQQAQ
这道题是分层图最短路问题
就是说在最短路的基础上有几条边的代价可以修改为零。
基本模型:
在给定的图上,有k次机会可以直接通过一条边,问起点与终点之间的最短路径
这样的题好像都挺裸的
做法是分层,
这里详细说一下吧
我们建立第000层至第kkk层一共k+1k+1k+1层图,每一层的边都是一样的,第iii层表示用掉iii次机会所能到达的最小价值。
int u=read()+1,v=read()+1,w=read();//因为此题点从0开始,个人习惯从1开始,就+1
for(int j=0;j<=k;++j){
add_edge(u+j*n,v+j*n,w);
add_edge(v+j*n,u+j*n,w);//每n个一层
}
像这样。
然后在每层图之间建边,因为有kkk次机会,所以,把第iii层的节点建一条通往i+1i+1i+1层的边,边权为000。
for(int j=0;j<k;++j)
add_edge(u+j*n,v+j*n+n,0),add_edge(v+j*n,u+j*n+n,0);
至此,边就建完啦!
然后就是一个一丁都不用改的最短路(个人推荐堆优dijkstradijkstradijkstra)
(关于SPFA,它死了)
对了!点数组的大小要开k+1k+1k+1倍!上午考试只开了kkk倍挂了一个点QAQQAQQAQ
奉上完整代码:
#include<iostream>
#include<cstdio>
#include<ctype.h>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
typedef pair<int,int> pairs;
priority_queue<pairs,vector<pairs>,greater<pairs> > q;
inline int read(){
int x=0,f=0;char ch=getchar();
while(!isdigit(ch))f|=ch=='-',ch=getchar();
while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
return f?-x:x;
}
int head[110007],cnt;
bool vis[110007];
int dis[110007];
int n,m,k,s,t,ans=99999999;
struct Edge{
int next,to,w;
}edge[20000007];
inline void add_edge(int from,int to,int w){
edge[++cnt].next=head[from];edge[cnt].w=w;
edge[cnt].to=to;head[from]=cnt;
}
inline void dijkstra(){
memset(dis,0x3f,sizeof dis);
dis[s]=0;q.push(make_pair(dis[s],s));
while(!q.empty()){
int x=q.top().second;q.pop();
if(vis[x])continue;vis[x]=1;
for(int i=head[x];i;i=edge[i].next){
int to=edge[i].to;
if(dis[to]>dis[x]+edge[i].w){
dis[to]=dis[x]+edge[i].w;
q.push(make_pair(dis[to],to));
}
}
}
}
int main(){
// freopen("pass.in","r",stdin);
// freopen("pass.out","w",stdout);
n=read(),m=read(),k=read();
s=read()+1,t=read()+1;
for(int i=1;i<=m;++i){
int u=read()+1,v=read()+1,w=read();
for(int j=0;j<k;++j)add_edge(u+j*n,v+j*n+n,0),add_edge(v+j*n,u+j*n+n,0);
for(int j=0;j<=k;++j){
add_edge(u+j*n,v+j*n,w);
add_edge(v+j*n,u+j*n,w);
}
}
dijkstra();
for(int i=0;i<=k;++i)ans=min(ans,dis[t+i*n]);
printf("%d",ans);
// fclose(stdin);fclose(stdout);
return 0;
}