vijos-p1139 2008.11.9
动态规划 vijos-p1139--我独立自主ac的第一道dp Hascomments
心得:1.一定要搞清楚每一个状态要怎样由上一个状态得到
2,要注意边界问题
描述 Description
xuzhenyi要办个签证。办证处是一座M层的大楼,1<=M<=100。
每层楼都有N个办公室,编号为1..N(1<=N<=500)。每个办公室有一个签证员。
签证需要让第M层的某个签证员盖章才有效。
每个签证员都要满足下面三个条件之一才会给xuzhenyi盖章:
1.这个签证员在1楼
2.xuzhenyi的签证已经给这个签证员的正楼下(房间号相同)的签证员盖过章了。
3.xuzhenyi的签证已经给这个签证员的相邻房间(房间号相差1,楼层相同)的签证员盖过章了。
每个签证员盖章都要收取一定费用,这个费用不超过1000000000。
找出费用最小的盖章路线,使签证生效
输入格式 Input Format
第1行两个整数M和N。
接下来M行每行N个整数,第i行第j个数表示第i层的第j个签证员收取的费用。
输出格式 Output Format
按顺序打出你经过的房间的编号,每行一个数。
如果有多条费用最小的路线,输出任意一条。
样例输入 Sample Input
34
1010 1 10
22 2 10
110 10 10
样例输出 Sample Output
3
3
2
1
1
刚开始时,一直有三组溢出,后来,误打误撞的,在矩阵的一周,都加了maxlongint,就不知怎么地的过了~可能就是因为这个,所以才不溢出了~~
庆祝下~~
在此期间,试过记录下路径,失败了,试过用非递归算法,失败了。
tips:
1. 传说中的双向dp,先从左向右来一遍,再从右向左来一遍,无论还是左右,都和正上方的比一下,取个最小值。
2. 从左向右的话,就单是从左向右,只可以从左边和上边取最小值,千万不可夹杂进去右边的值,否则,想一想,有些地方取得之可能会很小,但当它取那个值时,就不一定可以到达那个点了。从右向左时,存右边的值的数组,千万不可以左边的混到一起了,还是那句话,那一点在那个值不一定会去到
千万要左右分开来求,这一行最后都求完了,再从中选取最优值
program p1139;
const maxn=500;maxm=100;
var f,a:array[0..maxm+1,0..maxn+1]of longint;
x,y:array[0..maxn+1]of longint;
k:array[1..maxn*maxm]of longint;
i,j,l,m,n,ans,t:longint;
f1,f2:text;
procedure init;
begin
assign(f1,'in.in');reset(f1);
read(f1,m,n);
for i:=1 to m do
for j:=1 to n do
read(f1,a[i,j]);
l:=0;fillchar(k,sizeof(k),0);
ans:=maxlongint;
for i:=1 to n do
f[1,i]:=a[1,i];
for i:=1 to n do begin f[0,i]:=maxlongint;f[m+1,i]:=maxlongint;end;
for i:=1 to m do begin f[i,0]:=maxlongint;f[i,n+1]:=maxlongint;end;
{这个把三组溢出解决了}
end;
function min(x1,x2:longint):longint;
begin if x1>x2 then exit(x2) else exit(x1);end;
procedure dp;
var pp:longint;
begin
for i:=2 to m do
begin
x[1]:=a[i,1]+f[i-1,1];{从左向右即每个格子只能从它的上面和左面到达时}
for j:=2 to n do
x[j]:=min(f[i-1,j],x[j-1])+a[i,j];
y[n]:=a[i,n]+f[i-1,n]; {从右向左即每个格子只能从它的上面和右面到达时}
for j:=n-1 downto 1 do
y[j]:=min(f[i-1,j],y[j+1])+a[i,j];
for j:=1 to n do
begin
f[i,j]:=min(x[j],y[j]);{从中取一个最小的,记下来,此处,才可以从x,y中取最小值,否则,就会相互影响造成解的错误}
end;
end;
{ for i:=1 to m do
begin
for j:=1 to n do
write(f[i,j]:5);
writeln;
end;}
end;
procedure put(p:longint);
begin inc(l);k[l]:=p;end;
procedure print;
begin for i:=l downto 1 do writeln(k[i]);writeln(t);end;
procedure deal(p1,p2:longint);{递归输出}
var r,ss,t1,t2:longint;
begin
if p1=1 then begin print;exit;end;
r:=f[p1,p2]-a[p1,p2];
if f[p1-1,p2]=r then begin put(p2);deal(p1-1,p2);end
else if f[p1,p2-1]=r then begin put(p2-1);deal(p1,p2-1);end
else begin put(p2+1);deal(p1,p2+1);end;
end;
procedure doit;
begin
for i:=1 to n do
if f[m,i]<ans then begin ans:=f[m,i];t:=i;end;
deal(m,t);
end;
begin init;
dp;
doit;
end.
编译通过...
├测试数据01:答案正确... 0ms
├测试数据02:答案正确... 0ms
├测试数据03:答案正确... 0ms
├测试数据04:答案正确... 0ms
├测试数据05:答案正确... 0ms
├测试数据06:答案正确... 0ms
├测试数据07:答案正确... 0ms
├测试数据08:答案正确... 0ms
├测试数据09:答案正确... 0ms
-------------------------
Accepted有效得分:100 有效耗时:0ms
错误示例:
for i:=2 to m do
begin
x[1]:=a[i,1]+f[i-1,1];
for j:=2 to n do
x[j]:=min(f[i-1,j],x[j-1])+a[i,j];
f[i,n]:=a[i,n]+f[i-1,n];
for j:=n-1 downto 1 do
f[i,j]:=min(x[j],f[i,j+1]+a[i,j]);
这里x就影响到了y的值,假设,f[I,j]取了x[j]那么就是,这一点是从左边来的,而这一部分是要求从右边到左边的最优值,怎么可能会有左边过来的呢?
end;