【原题】【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.