题目大意:
有n个城市,编号为0到n-1。小B想从城市s到城市t。他选择了一家航空公司,这家公司有m种航线,每种航线连接了两个不同的城市。小B可以免费在最多k种航线上搭乘飞机。问小B最小花费是多少。
对于前30%的数据,2<=n<=50,1<=m<=300,k=0;
对于前50%的数据,2<=n<=600,1<=m<=6000,0<=k<=1;
对于前100%的数据,2<=n<=10000,1<=m<=50000,0<=k<=10,c<=1000.
题解:
spfa:
这题其实就跟平常的最短路spfa一样,不过多了个限制,所以我们设dis[i,j]表示从s走到第i个点,用了j次免费的机会,最短路是多少。
然后spfa+邻接表去做,做的时候
有2种可以转移:
则
①dis[t[i],j+1]>dis[s[i],j]
s[i]走到t[i],多用1次免费机会,且比它最优解小。
②dis[t[i],j]>dis[s[i],j]+w[i]
s[i]走到t[i],不用免费机会,走一次花费,且比它最优解小。
时间复杂度:O(2*M+TN)
T远远小于N
var
s,t,w,next:array [0..100001] of longint;
dis:Array [0..10001,0..11] of longint;
list:array [0..10001] of longint;
q:array [0..500001] of longint;
v:array [0..10001] of boolean;
ans,x,y,i,j,n,m,k,p,a1,b1,c1:longint;
procedure add(z1,z2,z3,ky:longint);
begin
s[ky]:=z1;
t[ky]:=z2;
w[ky]:=z3;
next[ky]:=list[z1];
list[z1]:=ky;
end;
function min(aa,bb:longint):longint;
begin
if aa>bb then exit(bb);
exit(aa);
end;
procedure spfa;
var
i,j,head,tail:longint;
begin
head:=0;
tail:=1;
q[1]:=x;
v[x]:=true;
for i:=0 to k do dis[x,i]:=0;
while head<tail do
begin
inc(head);
i:=list[q[head]];
while i>0 do
begin
for j:=0 to k do
if (dis[s[i],j]+w[i]<dis[t[i],j]) or (dis[s[i],j]<dis[t[i],j+1])
then begin
dis[t[i],j]:=min(dis[t[i],j],dis[s[i],j]+w[i]);
dis[t[i],j+1]:=min(dis[t[i],j+1],dis[s[i],j]);
if not(v[t[i]])
then begin
inc(tail);
q[tail]:=t[i];
v[t[i]]:=true;
end;
end;
i:=next[i];
end;
v[q[head]]:=false;
end;
end;
begin
readln(n,m,k);
readln(x,y);
for i:=1 to m do
begin
readln(a1,b1,c1);
inc(a1); inc(b1);
inc(p); add(a1,b1,c1,p);
inc(p); add(b1,a1,c1,p);
end;
for i:=1 to n do
for j:=0 to k do
dis[i,j]:=maxlongint div 3;
inc(x); inc(y);
spfa;
ans:=maxlongint;
for i:=0 to k do
ans:=min(ans,dis[y,i]);
writeln(ans);
end.