动态规划:矩阵取数

题目描述 
Description

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

输入描述 Input Description

第1行为两个用空格隔开的整数n和m。
第2~n+1 行为n*m矩阵,其中每行有m个用单个空格隔开的非负整数。

输出描述 Output Description

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

样例输入 Sample Input

2 3
1 2 3
3 4 2

样例输出 Sample Output

82

数据范围及提示 
Data Size & Hint
样例解释
第 1 次:第1 行取行首元素,第2 行取行尾元素,本次得分为1*21+2*21=6
第2 次:两行均取行首元素,本次得分为2*22+3*22=20
第3 次:得分为3*23+4*23=56。总得分为6+20+56=82
 
【限制】
60%的数据满足:1<=n, m<=30, 答案不超过10^16
100%的数据满足:1<=n, m<=80, 0<=aij<=1000

一个区间动规,但加了高精就变态多了。
f[i,j]表示以i为起点,j为终点所得的最大得分
f[i,j]=max(f[i+1,j]*2+init[i]
f[i,j-1]*2+init[j]);
答案不超过10^16,要用到高精加和乘
f[i,j,k]表示f[i,j]的第k位数

code:
var n,m:longint;
ii,i,j,k,c,v,b:longint;
init:array[0..100]of longint;
num1,num2:array[0..60]of longint;
f:array[1..100,1..100,0..60]of integer;
num:array[0..60]of integer;
len:longint;
function max(x,y:longint):longint;
begin if x>y
then exit(x)
else exit(y);
end;
begin readln(n,m);
fillchar(num,sizeof(num),0);
for ii:=1 to n do
begin for j:=1 to m do
read(init[j]);
fillchar(f,sizeof(f),0);
for i:=1 to m do
begin k:=init[i];
if k=0
then begin f[i,i,0]:=1;
f[i,i,1]:=0;
end
else begin j:=0;
while k<>0 do
begin inc(j);
f[i,i,j]:=k mod 10;
k:=k div 10;
end;
f[i,i,0]:=j;
end;
end;
                for i:=1 to m-1 do
                    for j:=1 to m-i do
                        begin fillchar(num1,sizeof(num1),0);
fillchar(num2,sizeof(num2),0);
for c:=0 to max(f[j+1,j+i,0],f[j,j+i-1,0]) do
begin num1[c]:=f[j,j+i-1,c];
num2[c]:=f[j+1,j+i,c];
end;
for c:=1 to max(num1[0],num2[0]) do
begin num1[c]:=num1[c]*2;
num2[c]:=num2[c]*2;
end;
for c:=1 to max(num1[0],num2[0])+1 do
begin num1[c+1]:=num1[c+1]+num1[c] div 10;
num1[c]:=num1[c] mod 10;
num2[c+1]:=num2[c+1]+num2[c] div 10;
num2[c]:=num2[c] mod 10;
end;
c:=num1[0]+1;
while (num1[c]=0)and(c>1) do dec(c);
num1[0]:=c;
c:=num2[0]+1;
while (num2[c]=0)and(c>1) do dec(c);
num2[0]:=c;
                              for c:=1 to max(num1[0],f[j+i,j+i,0]) do
begin num1[c+1]:=num1[c+1]+(num1[c]+f[j+i,j+i,c]) div 10;
num1[c]:=(num1[c]+f[j+i,j+i,c]) mod 10;
end;
len:=max(num1[0],f[j+i,j+i,0])+1;
while num1[len]=0 do dec(len);
num1[0]:=len;
for c:=1 to max(num2[0],f[j,j,0]) do
begin num2[c+1]:=num2[c+1]+(num2[c]+f[j,j,c]) div 10;
num2[c]:=(num2[c]+f[j,j,c]) mod 10;
end;
len:=max(num2[0],f[j,j,0])+1;
while num2[len]=0 do dec(len);
num2[0]:=len;
if num1[0]>num2[0]
then begin for c:=0 to num1[0] do
f[j,j+i,c]:=num1[c];
end;
if num2[0]>num1[0]
then begin for c:=0 to num2[0] do
f[j,j+i,c]:=num2[c];
end;
if num1[0]=num2[0]
then begin c:=num1[0];
while (c>=1)and(num1[c]=num2[c]) do
dec(c);
if num1[c]=num2[c]
then begin for v:=0 to num1[0] do
f[j,j+i,v]:=num1[v];
end;
if num1[c]<num2[c]
then begin for v:=0 to num2[0] do
f[j,i+j,v]:=num2[v];
end;
if num1[c]>num2[c]
then begin for v:=0 to num1[0] do
f[j,i+j,v]:=num1[v];
end;
end;
end;
for i:=1 to f[1,m,0] do
f[1,m,i]:=f[1,m,i]*2;
for i:=1 to f[1,m,0] do
begin f[1,m,i+1]:=f[1,m,i+1]+f[1,m,i] div 10;
f[1,m,i]:=f[1,m,i] mod 10;
end;
len:=f[1,m,0]+2;
while (f[1,m,len]=0)and(len>1) do
dec(len);
f[1,m,0]:=len;
len:=max(num[0],f[1,m,0]);
for i:=1 to len do
begin num[i+1]:=num[i+1]+(f[1,m,i]+num[i]) div 10;
num[i]:=(num[i]+f[1,m,i]) mod 10;
end;
len:=len+1;
while (num[len]=0)and(len>1) do dec(len);
num[0]:=len;
end;
for i:=num[0] downto 1 do
write(num[i]);
end.
原文地址:https://www.cnblogs.com/spiderKK/p/4899754.html