洛谷专题-动态规划TG.lv(1)
P1005 矩阵取数游戏(区间DP+高精度)
题意:
有一个n×m的矩阵,对于第i行,每次取走边缘的值A[i][j],增加这一行的得分x,求n行的最大得分总和
思路:
求n行最大得分和,每一行取数又不会影响到其他行,那么只要确保每一行得分最大,管好自家孩子就行了。(这个在动规中叫最优子结构)
每次取数是在边缘取,那么每次取数完剩下来的元素一定是在一个完整的一个区间中,又是求最优解,区间DP应运而生
状态:我们用DP[i][j]表示区间变为[i,j]时,获得的最大分数。
转移:当区间变为[i,j][i,j]时,上一次取数的时候区间一定是[i-1,j]或[i,j+1],从这两个状态转移即可。在第m-j+i-1次(这个请自行模拟)取走了A[i-1][j]或a[i][j-1]
dp[i][j]=max{dp[i+1][j]+2^(m-(j-i))×v[i],dp[i][j-1]+2^(m-(j-i))×v[j]}
终值(答案)因为题目中说要取完,但是空区间是DP不出来的,然后就得手动模拟每个长度为1的区间
#include<bits/stdc++.h> #define lll __int128 void print(lll x) { if (x==0) return; if (x) print(x/10); putchar(x%10+'0'); } int n,m; lll ans=0; int a[100]={0}; lll f[100][100]; lll p[100]={1}; lll dp() { memset(f,0,sizeof(f)); for(int i=1;i<=m;i++) { for(int j=m;j>=i;j--) { f[i][j]=std::max( f[i-1][j]+ p[m-j+i-1]*a[i-1] , f[i][j+1]+ p[m-j+i-1]*a[j+1] ); } } lll maxn=-1; for(int i=1;i<=m;i++) maxn=std::max(maxn,f[i][i]+a[i]*p[m]); return maxn; } int main() { for(int i=1;i<=90;i++) p[i]=p[i-1]<<1; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) scanf("%d",a+j); ans+=dp(); } if(ans==0) puts("0"); else print(ans); return 0; }