vijos-p1139 2008.11.9

来源:互联网 发布:超级山猫直升机数据 编辑:程序博客网 时间:2024/05/17 01:57

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;

 


0 0
原创粉丝点击