洛谷专题-动态规划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;
}
View Code

 

原文地址:https://www.cnblogs.com/overrate-wsj/p/12357588.html