题目
在艾泽拉斯,有n个城市。编号为1,2,3,…,n。
城市之间有m条双向的公路,连接着两个城市,从某个城市到另一个城市,会遭到联盟的攻击,进而损失一定的血量。
每次经过一个城市,都会被收取一定的过路费(包括起点和终点)。路上并没有收费站。
假设1为暴风城,n为奥格瑞玛,而他的血量最多为b,出发时他的血量是满的。
歪嘴哦不希望花很多钱,他想知道,在可以到达奥格瑞玛的情况下,他所经过的所有城市中最多的一次收取的费用的最小值是多少。
对于60%的数据,满足n≤200,m≤10000,b≤200
对于100%的数据,满足n≤10000,m≤50000,b≤1000000000
对于100%的数据,满足ci≤1000000000,fi≤1000000000,可能有两条边连接着相同的城市。
题解
歪嘴哦这个倒霉的孩子居然同时具有血量和过路费,两个代价,怎么办?于是考虑先确定一个值。确定过路费后,发现剩下的问题就是最短路,于是果断SPFA
那么怎么确定过路费呢?
考虑到题目要求“他所经过的所有城市中最多的一次收取的费用的最小值是多少”,于是可以看成求最大值里的最小值。这个嘛,最大值里的最小值,最小值里的最大值,统统果断二分。
二分答案,然后用SPFA判断当前答案是否行得通。
然而提交了
24
次都没有对
最后发现错的是什么地方呢,读入!
这个故事告诉我们哪怕是读入也可以让你的正确率暴跌
时间复杂度O(m log n)
代码
var
n,m,b,i,j,k,l,r,mid:longint;
a:array[1..100000,1..4]of longint;
s,w,c:array[0..10000]of longint;
ls:array[1..100000]of longint;
v:array[1..1000000]of longint;
d:array[1..50000]of boolean;
function spfa(key:longint):boolean;
var
l,r,i,j,k,t:longint;
begin
for i:=1 to n do
s[i]:=1000000000;
fillchar(d,sizeof(d),true);
l:=0;r:=1;v[r]:=1;s[1]:=0;d[1]:=false;
while l<r do
begin
inc(l);
i:=ls[v[l]];
while i>0 do
begin
if c[a[i,1]]>key then
begin
i:=a[i,4];
continue;
end;
if (s[a[i,1]]+a[i,3]<=b)and(s[a[i,1]]+a[i,3]<=s[a[i,2]]) then
begin
s[a[i,2]]:=s[a[i,1]]+a[i,3];
if d[a[i,2]] then
begin
inc(r);
v[r]:=a[i,2];
d[a[i,2]]:=false;
end;
end;
i:=a[i,4];
end;
d[v[l]]:=true;
end;
if s[n]<=b then exit(true) else exit(false);
end;
procedure qsort(l,r:longint);
var
i,j,key,t:longint;
begin
if l>=r then exit;
i:=l;j:=r;
key:=w[(l+r) div 2];
repeat
while w[i]<key do inc(i);
while w[j]>key do dec(j);
if i<=j then
begin
t:=w[i];w[i]:=w[j];w[j]:=t;
inc(i);dec(j);
end;
until i>j;
qsort(i,r);
qsort(l,j);
end;
begin
readln(n,m,b);
for i:=1 to n do
begin
readln(w[i]);
if w[i]>j then begin j:=w[i];r:=i;end;
end;
k:=w[1];if w[n]>k then k:=w[n];
c:=w;
qsort(1,n);
j:=0;
for i:=1 to m do
begin
inc(j);
readln(a[j,1],a[j,2],a[j,3]);
a[j,4]:=ls[a[j,1]];ls[a[j,1]]:=j;
inc(j);
a[j,1]:=a[j-1,2];a[j,2]:=a[j-1,1];a[j,3]:=a[j-1,3];
a[j,4]:=ls[a[j-1,2]];ls[a[j-1,2]]:=j;
end;
if not(spfa(w[n])) then begin writeln('AFK');halt;end;
l:=1;r:=n;
while l<r do
begin
mid:=(l+r) div 2;
if (k>w[mid]) or not(spfa(w[mid])) then l:=mid+1 else r:=mid;
end;
if spfa(w[l]) then
writeln(w[l])
else writeln(w[r]);
end.