SSL P2677 飞行fly

题目大意:
有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.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值