题目描述 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, 答案不超过1016
100%的数据满足:1<=n, m<=80, 0<=aij<=1000
这个题目就是一个动态规划,我们先把他每行单独拿出来看,设当矩阵剩下f[i,j]为以i为头,以j为尾的矩阵时,取到的最大值。根据题意可得只有通过f[i-1,j]和f[i,j+1]可以得到f[i,j]的状态。动态转移方程"f[i,j]=max(f[i-1,j]+f[i-1]*2^k,f[i,j+1]+f[j+1]*2^k
根据这个题目变态的数据,我们轻而易举就能得出,这个题目需要高精度。
代码风格略渣,不喜勿喷。
1 program jz; 2 type 3 sj=array[1..20]of longint; 4 5 var 6 a:array[0..81,0..81]of longint; 7 er:array[0..80]of sj; //2^k 8 e2,ans,ls,ll,lr,ls2:sj; 9 b:array[0..81,0..81]of sj; //f[i,j] 10 i,j,k,t,m,n:longint; 11 12 function bj(x,y:sj):boolean; //比较大小 13 var 14 i,l1,l2:longint; 15 begin 16 l1:=20; 17 l2:=20; 18 while (x[l1]=0) and (l1>1) do dec(l1); 19 while (y[l2]=0) and (l2>1) do dec(l2); 20 if (l1>l2) then exit(true); 21 if (l1<l2) then exit(false); 22 for i:=l1 downto 1 do 23 if (x[i]>y[i]) then exit(true) 24 else if (x[i]<y[i]) then exit(false); 25 exit(true); 26 end; 27 28 29 procedure gc(var x,y:sj); //高精度乘法 30 var 31 i,j,l1,l2:longint; 32 c:sj; 33 begin 34 l1:=20; 35 l2:=20; 36 while (x[l1]=0) and (l1>1) do dec(l1); 37 while (y[l2]=0) and (l2>1) do dec(l2); 38 fillchar(c,sizeof(c),0); 39 for i:=1 to l1 do 40 for j:=1 to l2 do 41 begin 42 c[i+j-1]:=c[i+j-1]+x[i]*y[j]; 43 c[i+j]:=c[i+j]+c[i+j-1] div 10000; 44 c[i+j-1]:=c[i+j-1] mod 10000; 45 end; 46 for i:=1 to l1+l2 do 47 if (c[i]>9999) then 48 begin 49 c[i+1]:=c[i] div 10000; 50 c[i]:=c[i] mod 10000; 51 end; 52 x:=c; 53 end; 54 55 56 procedure gd(var x,y:sj); //高精度加法 57 var 58 i,j,l1,l2:longint; 59 begin 60 l1:=20; 61 l2:=20; 62 while (x[l1]=0) and (l1>1) do dec(l1); 63 while (y[l2]=0) and (l2>1) do dec(l2); 64 if (l1<l2) then l1:=l2; 65 for i:=1 to l2 do 66 begin 67 x[i]:=x[i]+y[i]; 68 x[i+1]:=x[i+1]+x[i] div 10000; 69 x[i]:=x[i] mod 10000; 70 end; 71 end; 72 73 74 begin 75 readln(n,m); 76 fillchar(a,sizeof(a),0); 77 for i:=1 to n do 78 for j:=1 to m do 79 read(a[i,j]); 80 e2[1]:=2; 81 er[1][1]:=2; 82 for i:=2 to m do //求2^k 83 begin 84 er[i]:=er[i-1]; 85 gc(er[i],e2); 86 end; 87 fillchar(ans,sizeof(ans),0); 88 for i:=1 to n do 89 begin 90 fillchar(ls2,sizeof(ls2),0); 91 for j:=1 to m do 92 for k:=m downto j do 93 begin 94 t:=j-0+m-k-1; 95 fillchar(ll,sizeof(ll),0); 96 fillchar(lr,sizeof(lr),0); 97 if not ((j=1) and (k=m)) then 98 begin 99 ll[1]:=a[i,j-1]; 100 gc(ll,er[t]); 101 gd(ll,b[j-1,k]); 102 lr[1]:=a[i,k+1]; 103 gc(lr,er[t]); 104 gd(lr,b[j,k+1]); 105 if bj(ll,lr) then 106 b[j,k]:=ll 107 else b[j,k]:=lr; 108 if (j=k) then 109 begin 110 fillchar(ls,sizeof(ls),0); 111 ls[1]:=a[i,j]; 112 gc(ls,er[t+1]); 113 gd(ls,b[j,k]); 114 b[j,k]:=ls; 115 if bj(b[j,k],ls2) then 116 ls2:=b[j,k]; 117 end; 118 end; 119 end; 120 gd(ans,ls2); 121 end; 122 t:=20; 123 while (ans[t]=0) and (t<>0) do 124 dec(t); 125 if (t=0) then write(0); 126 for i:=t downto 1 do 127 if (ans[i]>=1000) or (i=t) then 128 write(ans[i]) 129 else 130 if (ans[i]>=100) then 131 write(0,ans[i]) 132 else 133 if (ans[i]>=10) then 134 write('00',ans[i]) 135 else write('000',ans[i]); 136 writeln; 137 end.