问题
背景 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.