vijos-p1139 2008.11.9

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值