算法:二分答案+最短路
再次重申一个很重要的内容,一般求最小值的最大值或最大值的最小值都可以用二分答案来做。
说说本题的思路吧。
用数组v[]记录到某一个点的最短边数,然后用mid表示要二分的那个答案(也是最短路径中的最长边),那么这条路径中所有比mid大的边肯定都要使用神功,用v[]记录一下。
第一次将mid设0,目的是求从1走到n最少需要走几条边,如果求出v[n]<=神功数目,那么答案就是0,如果依旧没变,那么也就是走不到,输出-1。
再次重申一个很重要的内容,一般求最小值的最大值或最大值的最小值都可以用二分答案来做。
说说本题的思路吧。
用数组v[]记录到某一个点的最短边数,然后用mid表示要二分的那个答案(也是最短路径中的最长边),那么这条路径中所有比mid大的边肯定都要使用神功,用v[]记录一下。
第一次将mid设0,目的是求从1走到n最少需要走几条边,如果求出v[n]<=神功数目,那么答案就是0,如果依旧没变,那么也就是走不到,输出-1。
上述条件都不满足的话进行二分,以最小权值和最大权值为左右边界二分,以当前的mid再求最短路得v[n],若v[n]小于等于神功数目则继续向左找(看能否有更加的答案),否则就向右。
program P1163;
const
maxn=1001;
var
v:array [0..maxn] of longint;
b:array [0..maxn] of boolean;
d:array [0..maxn,0..maxn] of longint;
tem,n,m,tot,maxo:longint;
procedure init;
var
i,x,y,dis:longint;
begin
maxo:=-maxlongint;
readln(n,m,tot);
for i:=1 to m do
begin
readln(x,y,dis);
d[x,y]:=dis;
d[y,x]:=dis;
if dis>maxo then maxo:=dis;
end;
writeln(maxo);
end;
function minn(x,y:longint):longint;
begin
if x<y then exit(x) else exit(y);
end;
function dijkstra(mid:longint):longint;
var
i,j,min,p:longint;
begin
fillchar(v,sizeof(v),100);
fillchar(b,sizeof(b),false);
v[1]:=0;
for i:=1 to n do
begin
min:=maxlongint;
for j:=1 to n do
begin
if (v[j]<min) and (not b[j]) then
begin
min:=v[j];
p:=j;
end;
end;
b[p]:=true;
for j:=1 to n do
begin
if ((d[p,j]>mid) and (not b[j])) then v[j]:=minn(v[j],v[p]+1)
else if (not b[j]) and (d[p,j]>0) then v[j]:=minn(v[j],v[p]);
end;
end;
exit(v[n]);
end;
function erfen(l,r:longint):longint;
var
mid:longint;
begin
if l=r then exit(l);
mid:=(l+r) >> 1;
if dijkstra(mid)<=tot then exit(erfen(l,mid)) else exit(erfen(mid+1,r));
end;
begin
assign(input,'P1163.in'); reset(input);
assign(output,'P1163.out'); rewrite(output);
init;
tem:=dijkstra(0);
if tem=v[0] then writeln(-1)
else if tem<=tot then writeln(0)
else writeln(erfen(1,maxo));
close(input); close(output);
end.