题目描述
A l i c e Alice Alice和 B o b Bob Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司。该航空公司一共在 n n n个城市设有业务,设这些城市分别标记为 0 0 0到 n − 1 n-1 n−1,一共有 m m m种航线,每种航线连接两个城市,并且航线有一定的价格。
A l i c e Alice Alice和 B o b Bob Bob现在要从一个城市沿着航线到达另一个城市,途中可以进行转机。航空公司对他们这次旅行也推出优惠,他们可以免费在最多 k k k种航线上搭乘飞机。那么 A l i c e Alice Alice和 B o b Bob Bob这次出行最少花费多少?
输入输出格式
输入格式:
数据的第一行有三个整数,
n
n
n,
m
m
m,
k
k
k,分别表示城市数,航线数和免费乘坐次数。
第二行有两个整数,
s
s
s,
t
t
t,分别表示他们出行的起点城市编号和终点城市编号。
接下来有m行,每行三个整数,
a
a
a,
b
b
b,
c
c
c,表示存在一种航线,能从城市
a
a
a到达城市
b
b
b,或从城市
b
b
b到达城市
a
a
a,价格为
c
c
c。
输出格式:
只有一行,包含一个整数,为最少花费。
输入输出样例
输入样例#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
≤
50
2 \le n \le 50
2≤n≤50,
1
≤
m
≤
300
1 \le m \le 300
1≤m≤300,
k
=
0
k=0
k=0,
对于50%的数据,
2
≤
n
≤
600
2 \le n \le 600
2≤n≤600,
1
≤
m
≤
6000
1 \le m \le 6000
1≤m≤6000,
0
≤
k
≤
1
0\le k \le 1
0≤k≤1;
对于100%的数据,
2
≤
n
≤
10000
2 \le n \le 10000
2≤n≤10000,
1
≤
m
≤
50000
1 \le m \le 50000
1≤m≤50000,
0
≤
k
≤
10
0≤k≤10
0≤k≤10,
0
≤
c
≤
10000
≤
s
,
t
<
n
0 \le c \le 10000≤s,t<n
0≤c≤10000≤s,t<n,
0
≤
a
0≤a
0≤a,
b
<
n
b<n
b<n,
a
≠
b
a≠b
a̸=b,
0
≤
c
≤
1000
0≤c≤1000
0≤c≤1000
今上午考试考了这道题,数组开小了 Q A Q QAQ QAQ
这道题是分层图最短路问题
就是说在最短路的基础上有几条边的代价可以修改为零。
基本模型:
在给定的图上,有k次机会可以直接通过一条边,问起点与终点之间的最短路径
这样的题好像都挺裸的
做法是分层,
这里详细说一下吧
我们建立第 0 0 0层至第 k k k层一共 k + 1 k+1 k+1层图,每一层的边都是一样的,第 i i i层表示用掉 i i i次机会所能到达的最小价值。
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个一层
}
像这样。
然后在每层图之间建边,因为有 k k k次机会,所以,把第 i i i层的节点建一条通往 i + 1 i+1 i+1层的边,边权为 0 0 0。
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);
至此,边就建完啦!
然后就是一个一丁都不用改的最短路(个人推荐堆优 d i j k s t r a dijkstra dijkstra)
(关于SPFA,它死了)
对了!点数组的大小要开 k + 1 k+1 k+1倍!上午考试只开了 k k k倍挂了一个点 Q A Q QAQ QAQ
奉上完整代码:
#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;
}