TYVJ P1061 题解
表示这个题想的很dt。
一开始就想f[i,a,b,c]表示第i个请求,三个人在a,b,c的最小代价。但是肯定是杀伤力超大任何评测机都闻风丧胆的TLE+MLE程序……
后来就想能不能把i压缩掉,结果想了很长时间无果,发现如果第i时间那么它上一次一定有一个点是i-1要求的位置,还是不能搞,因为不知道怎嘛把i去掉……
后来无语看了题解,发现是把a,b,c中压缩了一维,因为对于确定的i,至少有一个人的位置是确定的。
所以用f[i,a,b]表示,在第i个请求中,三个人分别在a,b,p[i]的最小代价。p[i]就是请求位置。
最好用主动更新,f[i-1,a,b]去更新。
如果是从p[i-1]到p[i],那么f[i,a,b]:=min(f[i,a,b],f[i-1,a,b]+c[p[i-1],p[i]]);
如果是a到p[i],那么f[i,p[i-1],b]:=min(f[i,p[i-1],b],f[i-1,a,b]+c[a,p[i]]);
如果是b到p[i],那么f[i,a,p[i-1]]:=min(f[i,a,p[i-1]],f[i-1,a,b]+c[b,p[i]]);
好了,一开始把第一个询问赋初值,循环就行了。还有,需要滚动数组,开上面的状态也会开爆的……
View Code
var
f:array[0..1,1..200,1..200] of longint;
c:array[1..200,1..200] of longint;
p:array[1..1000] of longint;
n,m:longint;
ans,i,j,k:longint;
function min(a,b:longint):longint;
begin
if a>b then exit(b) else exit(a);
end;
begin
readln(n,m);
for i:=1 to n do
for j:=1 to n do
read(c[i,j]);
for i:=1 to m do read(p[i]);
filldword(f,sizeof(f) shr 2,maxlongint);
f[0,2,3]:=c[1,p[1]]; f[0,1,2]:=c[3,p[1]]; f[0,1,3]:=c[2,p[1]];
for i:=2 to m do
begin
for j:=1 to n do
for k:=1 to n do
if (f[0,j,k]<>maxlongint) and (j<>k) and (k<>p[i-1]) and (j<>p[i-1]) then
begin
f[1,j,k]:=min(f[1,j,k],f[0,j,k]+c[p[i-1],p[i]]);
f[1,p[i-1],k]:=min(f[1,p[i-1],k],f[0,j,k]+c[j,p[i]]);
f[1,j,p[i-1]]:=min(f[1,j,p[i-1]],f[0,j,k]+c[k,p[i]]);
end;
for j:=1 to n do
for k:=1 to n do
begin
f[0,j,k]:=f[1,j,k];
f[1,j,k]:=maxlongint;
end;
end;
ans:=maxlongint;
for i:=1 to n do
for j:=1 to n do
begin
ans:=min(ans,f[0,i,p[m]]);
ans:=min(ans,f[0,p[m],j]);
ans:=min(ans,f[0,i,j]);
end;
writeln(ans);
end.