【原题】【noip2007 T3】矩阵取数

问题

背景 Background

NOIP2007年提高组第三道

描述 Description

帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素a[i,j]均为非负整数。游戏规则如下:
1. 每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有元素;
2. 每次取走的各个元素只能是该元素所在行的行首或行尾;
3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号);
4. 游戏结束总得分为m次取数得分之和。
帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。

输入格式 Input Format

输入文件game.in包括n+1行:
第1行为两个用空格隔开的整数n和m。
第2~n+1行为n*m矩阵,其中每行有m个用单个空格隔开的非负整数。

输出格式 Output Format

输出文件game.out仅包含1行,为一个整数,即输入矩阵取数后的最大得分。

 

分析

显然是一道动规题,怎么办捏?仔细想一下,我们发现,这个矩阵的n行互不影响,m次取数对于每行的最优值都是没有影响的,所以我们可以考虑将矩阵变成数列,逐次对美一行进行动规,那么显然,最后的答案就是每行的最优值之和。

一旦我们有了如上的思路,事情就变得很简单了。方程f[i,j]表示去了i次,从左边取走了j个。我们可以得到一下的转移方程f[i,j]:=max{f[i-1,j-1]+a[j]*cifang[i],f[i-1,j]+a[m-i+j+1]*cifang[i]}要对次方数组进行预处理。然后求解

由于题目的数据范围,所以要用压四位的高精度。

有用到运算符重载,不懂得童鞋百度一哈吧

反思

自己的方程一开始存在问题,尤其是第二种情况时a数组的下标没有找对。以后要细心,仔细推。

这个题看似很难,其实可以转化为很简单的问题,关键是能看出问题的本质,找出方程。不要被惯性思维限制,敢于想,敢于转化问题。

code

program liukee;
type
  arr=array[0..100] of longint;
var
  f:array[-1..81,-1..81] of arr;
  a:array[1..80] of longint;
  cifang:array[0..80] of arr;
  ans,tt:arr;
  n,m,i,j,r,k,zu:longint;
function max(a,b:arr):arr;
var
  z:integer;
begin
  if a[0]>b[0] then
    begin
      max:=a;
      exit;
    end;
  if b[0]>a[0] then
    begin
      max:=b;
      exit;
    end;
  for z:=a[0] downto 1 do
    begin
      if a[z]>b[z] then
        begin
          max:=a;
          exit;
        end;
      if b[z]>a[z] then
        begin
          max:=b;
          exit;
        end;
    end;
  max:=a;
end;
operator *(a:arr;x:longint)c:arr;
var
  i:longint;
begin
  fillchar(c,sizeof(c),0);
  c[0]:=a[0];
  for i:=1 to c[0] do
    c[i]:=a[i]*x;
  for i:=1 to c[0] do
  begin
    inc(c[i+1],c[i] div 10000);
	c[i]:=c[i] mod 10000;
  end;
  while(c[c[0]+1]>0)do inc(c[0]);

end;

operator +(a,b:arr)c:arr;
var
  i:longint;
begin
  fillchar(c,sizeof(c),0);
  if a[0]>b[0] then c[0]:=a[0]
               else c[0]:=b[0];
  for i:=1 to c[0] do inc(c[i],a[i]+b[i]);
  for i:=1 to c[0] do
  begin
    inc(c[i+1],c[i] div 10000);
	c[i]:=c[i] mod 10000;
  end;
  while(c[c[0]+1]>0) do inc(c[0]);
end;

procedure outit(a:arr);
var
  i:longint;
begin
  write(a[a[0]]);
  for i:=a[0]-1 downto 1 do
  begin
    write(a[i] div 1000);
	  write(a[i] div 100 mod 10);
	  write(a[i] div 10 mod 10);
    write(a[i] mod 10)
  end;
	writeln;
end;

begin
assign(input,'in.txt');reset(input);
  readln(n,m);
  cifang[0][0]:=1; cifang[0][1]:=1;
  for i:=1 to m do cifang[i]:=cifang[i-1]*2;
 fillchar(ans,sizeof(ans),0);
 for zu:=1 to n do
  begin

  fillchar(f,sizeof(f),0);
  for i:=1 to m do read(a[i]);
		
	for i:=1 to m do
	  for j:=0 to m do
	  begin
	  
	    f[i,j]:=max(f[i,j],f[i-1,j-1]+cifang[i]*a[j]);
	  
 		  f[i,j]:=max(f[i,j],f[i-1,j]+cifang[i]*a[m-i+j+1]);
	  end;
  fillchar(tt,sizeof(tt),0);
	for i:=1 to m do tt:=max(tt,f[m,i]);
	ans:=ans+tt;
  end;
  outit(ans);
end.


posted @ 2010-11-09 18:05  liukee  阅读(752)  评论(0编辑  收藏  举报