【洛谷 1462】通往奥格瑞玛的道路

问题描述
在艾泽拉斯,有n个城市。编号为1,2,3,…,n。

城市之间有m条双向的公路,连接着两个城市,从某个城市到另一个城市,会遭到联盟的攻击,进而损失一定的血量。
没经过一个城市,都会被收取一定的过路费(包括起点和终点)。路上并没有收费站。
假设1为暴风城,n为奥格瑞玛,而他的血量最多为b,出发时他的血量是满的。
歪嘴哦不希望花很多钱,他想知道,在可以到达奥格瑞玛的情况下,他所经过的所有城市中最多的一次收取的费用的最小值是多少。
输入
第一行3个正整数,n,m,b。分别表示有n个城市,m条公路,歪嘴哦的血量为b。
接下来有n行,每行1个正整数,fi。表示经过城市i,需要交费fi元。
再接下来有m行,每行3个正整数,ai,bi,ci(1<=ai,bi<=n)。表示城市ai和城市bi之间有一条公路,如果从城市ai到城市bi,或者从城市bi到城市ai,会损失ci的血量。
输出
仅一个整数,表示歪嘴哦交费最多的一次的最小值。
如果他无法到达奥格瑞玛,输出AFK。
样例输入
4 4 8
8
5
6
10
2 1 2
2 4 1
1 3 4
3 4 3
样例输出
10
算法讨论
我们将每个城市的过路费记录下来,找出最大最小值,在这两者之间二分,记录当前二分值,跑一遍spfa,若二分值可以让歪嘴哦达到终点,说明歪嘴哦有可能用更少的钱达到终点,向左二分;若不能,则说明歪嘴哦要用更多的钱达到终点,向右二分。直到l>=r得出答案。

const
  maxn=100000;
  maxm=500000;
var
  x,y,next:array[1..maxm] of longint;
  w:array[1..maxm] of int64;
  v,list,ls:array[1..maxn] of longint;
  d,w1:array[1..maxn] of int64;
  i,j,n,m,p:longint;
  min,max,b:int64;

function spfa(ww:int64):boolean;
var
  hd,tl,t:int64;
  i:longint;
begin
  fillchar(v,sizeof(v),0);
  hd:=0; tl:=1;
  v[1]:=1;
  list[1]:=1; 
  for i:=1 to n do
    d[i]:=10*maxlongint;
  d[1]:=w[1];
  while hd<>tl do
    begin
      inc(hd);
      t:=ls[list[hd]];
      while t>0 do
        begin
          if (w1[y[t]]<=ww) and (d[x[t]]+w[t]<d[y[t]])
            then begin
                   d[y[t]]:=d[x[t]]+w[t];
                   if v[y[t]]=0
                     then begin
                            v[y[t]]:=1;
                            inc(tl);
                            list[tl]:=y[t]
                          end;
                 end;
          t:=next[t]
        end;
      v[list[hd]]:=0
    end;
  if d[n]<=b
    then exit(true)
    else exit(false)
end;

procedure half(l,r:longint);
var
  mid:int64;
begin
  if l>=r
    then begin
           if spfa(l)
             then write(l)
             else write('AFK');
           halt
         end;
  mid:=(l+r) div 2;
  if spfa(mid)
    then half(l,mid)
    else half(mid+1,r)
end;

begin
  read(n,m,b);
  min:=10*maxlongint;
  for i:=1 to n do
    begin
      read(w1[i]);
      if w1[i]<min
        then min:=w1[i];
      if w1[i]>max
        then max:=w1[i]
    end;
  for i:=1 to m do
    begin
      inc(p);
      read(x[p],y[p],w[p]);
      next[p]:=ls[x[p]];
      ls[x[p]]:=p;
      inc(p);
      x[p]:=y[p-1]; y[p]:=x[p-1]; w[p]:=w[p-1];
      next[p]:=ls[x[p]];
      ls[x[p]]:=p
    end;
  half(min,max)
end.

这里写图片描述
Pixiv ID:61813706

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值