问题描述
在艾泽拉斯,有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