解题报告 PATH
Path
【Description】
Loongint非常喜欢Dota这款游戏~但是他总是被Dota复杂的地图困扰,有时候甚至会因为地图太复杂而失去了自己Gank和Farm的节奏。所以他需要你的帮忙。
地图上一共有n个关键位置,每个关键位置有一个关键值Vi, 关键位置之间有m条双向的通路,每条通路有其通行值Ci,我们定义两关键位置之间的距离为其间的通路的通行值和加上路径上关键值最大的关键位置(包括起点终点)的关键值。
Loongint现在有Q个询问,对于每个询问,你需要告诉他a关键位置和b关键位置间的最短距离。
【Input Format】
输入第1行为三个数 n,m,q,第2行到第n+1行表示关键位置的关键值Vi,第n+2到第n+m+1行表示通路的起始位置和通行值,第n+m+2到第n+m+q+1行表示q个询问,每个询问给出a,b。
【Output Format】
输出q行,每行对应一个询问的最短距离。
【Sample Input】
5 7 2
2
5
3
3
4
1 2 3
1 3 2
2 5 3
5 3 1
5 4 1
2 4 3
3 4 4
1 4
2 3
【Sample Output】
8
9
【Data】
对于40%的数据 |
N≤40,M≤100 |
Q≤100 |
对于60%的数据 |
N≤100,M≤2500 |
Q≤1000 |
对于100%的数据 |
N≤250,M≤10,000 |
Q≤10,000;Vi,Ci≤100,000 |
【Path】
因为询问有很多,而且询问对象都是相似的,所以一般的解法都是预处理出所有的答案,然后用O(1)的时间回答所有的问题。
—————算法1———–
非常明显的解法就是直接枚举某个点K作为可允许的可以最大关键值点,并用K以及权值小于K的点来更新所有点对的最小距离,更新点对用到floyd,floyd效率是O(N³),枚举可允许最大关键点用O(N),所以总的复杂度是O(N^4)。不言而喻,这样肯定是对的,所以60分是白送的。
—————算法2———–
有了解法一,应该想到充分利用floyd的性质:DP。最外层的K表示的就是经过了前K个点,而解法一中O(N)的枚举正是枚举了某一个中介点,我们能否将其结合起来呢?答案是肯定的。由于floyd最外层的K表示的是经过了前K个点,而且这前K个点的顺序对floyd结果是没有影响的,所以假如用前K个点就可以确定最大关键值点,那么就可以省略解法一中O(N)的枚举。于是我们先将所有的点按关键值从小到大排序,最外层的K既表示的就是当前用到的最大的权值,又保持了floyd的性质,直接可以出结果。这样总的复杂度就是O(N³)。
所以,代码就有了。
Program Path(input,output);
var
f,d:array[0..251,0..251] of longint;
id,a:array[0..251] of longint;
ans,i,j,k,n,m1,w,m2:longint;
function max(x,y:longint):longint;
begin
if x>y then exit(x);
exit(y);
end;
begin
assign(input,'Path.in'); reset(input);
assign(output,'Path.out'); rewrite(output);
read(n,m1,m2);
fillchar(d,sizeof(d),10);
fillchar(f,sizeof(f),10);
for i:=1 to n do
begin
id[i]:=i;
readln(a[i]);
d[i,i]:=0;
end;
for i:=1 to n do
for j:=i+1 to n do
if a[id[i]]>a[id[j]] then
begin
k:=id[i];
id[i]:=id[j];
id[j]:=k;
end;
for i:=1 to m1 do
begin
readln(j,k,w);
if d[j,k]>w then
begin
d[j,k]:=w;
d[k,j]:=w;
end;
end;
for w:=1 to n do
begin
k:=id[w];
for i:=1 to n do
for j:=1 to n do
if d[i,j]>d[i,k]+d[k,j] then
d[i,j]:=d[i,k]+d[k,j];
for i:=1 to n do
for j:=1 to n do
if f[i,j]>d[i,j]+max(a[i],max(a[k],a[j])) then
f[i,j]:=d[i,j]+max(a[i],max(a[k],a[j]));
end;
for i:=1 to m2 do
begin
readln(j,k);
writeln(f[j,k]);
end;
close(input); close(output);
end.