问题描述
有n个城市,编号为0到n-1。小B想从城市s到城市t。他们选择了一家航空公司,这家公司有m种航线,每种航线连接了两个不同的城市。看在小B是个妹子的份上,航空公司的老总给了小B一点优惠:小B可以免费在最多k种航线上搭乘飞机。问小B最小花费是多少。
输入
第一行三个整数n,m,k,分别表示城市数量,航线数量和免费搭乘的航线数量。
第二行两个整数s,t,表示起点和终点。
接下来m行,每行三个整数a.b.c,表示一种航线,即可以从a到b,也可以从b到a,花费为c。
输出
一行一个整数,表示最小花费。
样例输入
5 6 1
0 4
0 1 5
1 2 5
2 3 5
3 4 5
2 3 3
0 2 100
样例输出
8
算法讨论
分层图spfa,dis[i,j]表示从起点走到点i,用了j次优惠的最小费用。枚举是否用优惠往后转移即可。
#include <cstdio>
#include <iostream>
using namespace std;
#define maxn 100000
#define maxm 500000
struct edge
{
int f,t,n,c;
}a[maxm];
int ls[maxn],d[maxn][15],list[maxn];
bool v[maxn];
int n,m,k,s,t,e;
int init()
{
scanf("%d%d%d",&n,&m,&k);
scanf("%d%d",&s,&t);
for (int i=0;i<m;i++)
ls[i]=-1;
for (int i=1;i<=m;i++)
{
e++;
scanf("%d%d%d",&a[e].f,&a[e].t,&a[e].c);
a[e].n=ls[a[e].f];
ls[a[e].f]=e;
e++;
a[e].f=a[e-1].t; a[e].t=a[e-1].f; a[e].c=a[e-1].c;
a[e].n=ls[a[e].f];
ls[a[e].f]=e;
}
for (int i=0;i<n;i++)
for (int j=0;j<=k;j++)
d[i][j]=2147483647;
for (int j=0;j<=k;j++)
d[s][j]=0;
}
int spfa()
{
int hd=0,tl=0,t=0;
tl=1;
list[1]=s;
v[s]=1;
while (hd!=tl)
{
hd++;
t=ls[list[hd]];
while (t>-1)
{
for (int j=0;j<=k;j++)
if (d[a[t].f][j]+a[t].c<d[a[t].t][j] || d[a[t].f][j]<d[a[t].t][j+1])
{
d[a[t].t][j]=min(d[a[t].t][j],d[a[t].f][j]+a[t].c);
d[a[t].t][j+1]=min(d[a[t].t][j+1],d[a[t].f][j]);
if (!v[a[t].t])
{
v[a[t].t]=1;
tl++;
list[tl]=a[t].t;
}
}
t=a[t].n;
}
v[list[hd]]=0;
}
}
int main()
{
init();
spfa();
printf("%d",d[t][k]);
return 0;
}
Pixiv ID:33737282