题目大意:
农场中有N片草地,并且有M条双向道路连接草地A_j和B_j。FJ已经在连接A_j和B_j的双向道路上设置一个过路费L_j。
可能有多条道路连接相同的两片草地,但是不存在一条道路连接一片草地和这片草地本身。
在每片草地上面也设置了一个过路费C_i。从一片草地到另外一片草地的费用,是经过的所有道路的过路费之和,加上经过的所有的草地(包括起点和终点)的过路费的最大值。
接受K个问题并且输出每个询问对应的最小花费。第i个问题包含两个数字s_i和t_i,表示起点和终点的草地。
1 <= N <= 250
1 <= M <= 10000
1<= K <= 10,000
1 <= C_i <= 100000
1 <= L_j <= 100,000
1 <= A_j <= N; 1 <= B_j <= N
1 <= s_i <= N; 1 <= t_i <= N; s_i != t_i
保证奶牛们从任意一片草地出发可以抵达任意一片的草地。
题解:
最短路变形:
这题N那么小,很明显floyd就可以了,不过因为有过路费的问题,所以floyd的解很明显无法到达最优!
所以我们该怎么做呢?
分析发现,我们可以把它的中转点k给排序,
这样去做floyd,就可以保证过路费只在a_i,a_k,a_j中了!
然后
dp[i,j]表示i到j不包括最大过路费的最小花费。
rp[i,j]表示包括最大过路费i到j的最小花费。
然后可以推出:
dp[i,j]=min(dp[i,j],dp[i,k]+d[k,j])
rp[i,j]=min(rp[i,j],dp[i,j]+max{a_i,a_k,a_j})
为什么是d[i,j]+max{a_i,a_k,a_j}呢?
如果i到j的最小花费的路上,不含k这个点这么办?
一开始我对这个有点疑惑,
但我发现,
如果dp[i,j]没有被中转点k更新,
那么【dp[i,j]+max{a_i,a_k,a_j}】是绝对无法更新rp[i,j]的,这个自己想想就知道了!
var
dp,rp:Array [0..251,0..251] of longint;
c:array [0..251,1..2] of longint;
a:array [0..251] of longint;
x,y,z,i,j,k,l,n,m,p:longint;
function min(aa,bb:longint):longint;
begin
if aa>bb then exit(bb);
exit(aa);
end;
function max(aa,bb:longint):longint;
begin
if aa>bb then exit(aa);
exit(bb);
end;
begin
assign(input,'toll.in'); reset(input);
assign(output,'toll.out'); rewrite(output);
readln(n,m,p);
for i:=1 to n do
begin
readln(a[i]);
c[i,1]:=a[i];
c[i,2]:=i;
end;
for i:=1 to n-1 do
for j:=i+1 to n do
if c[i,1]>c[j,1] then
begin
c[0]:=c[i];
c[i]:=c[j];
c[j]:=c[0];
end;
for i:=1 to n do
for j:=1 to n do
if i<>j
then begin
dp[i,j]:=maxlongint div 5;
rp[i,j]:=maxlongint div 5;
end
else rp[i,i]:=a[i];
for i:=1 to m do
begin
readln(x,y,z);
dp[x,y]:=min(dp[x,y],z);
dp[y,x]:=dp[x,y];
end;
for l:=1 to n do
begin
k:=c[l,2];
for i:=1 to n do
for j:=1 to n do
if (i<>j) and (i<>k) and (j<>k) then
begin
dp[i,j]:=min(dp[i,j],dp[i,k]+dp[k,j]);
rp[i,j]:=min(rp[i,j],dp[i,j]+max(a[k],max(a[i],a[j])));
end;
end;
for i:=1 to p do
begin
readln(x,y);
writeln(rp[x,y]);
end;
close(input); close(output);
end.