洛谷P1005 矩陣取數遊戲【記憶化搜尋】
阿新 • • 發佈:2018-12-15
題目描述
帥帥經常跟同學玩一個矩陣取數遊戲:對於一個給定的的矩陣,矩陣中的每個元素 均為非負整數。遊戲規則如下:
每次取數時須從每行各取走一個元素,共個。經過次後取完矩陣內所有元素; 每次取走的各個元素只能是該元素所在行的行首或行尾; 每次取數都有一個得分值,為每行取數的得分之和,每行取數的得分 = 被取走的元素值 ,其中ii表示第i次取數(從1開始編號); 遊戲結束總得分為m次取數得分之和。 帥帥想請你幫忙寫一個程式,對於任意矩陣,可以求出取數後的最大得分。
輸入格式:
輸入檔案包括n+1行:
第1行為兩個用空格隔開的整數n和m
第2~n+1行為n×m矩陣,其中每行有m個用單個空格隔開的非負整數。
輸出格式:
輸出檔案僅包含1行,為一個整數,即輸入矩陣取數後的最大得分。
說明
資料範圍: 60%的資料滿足:,答案不超過 100%的資料滿足:
題目分析
被高精度活活卡死的記搜大水題
試著把取數方式看作 在每一行按一定的順序依次取完m個數,總共n行所以取n次
顯然與原來的方式是等價的
那麼我們可以依次計算每一行取數總分最大值
狀態轉移方程 加上記憶化即可
活活被卡死在高精度,實所無奈直接用了__int128
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
typedef __int128 lt;
lt read()
{
lt f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
void print(lt x)
{
if(x<0){putchar('-');x=-x;}
if(x>9)print(x/10);
putchar(x%10+'0');
}
const int maxn=90;
int n,m;
lt a[maxn][maxn];
lt dp[maxn][maxn][maxn],ans;
lt qpow(lt a,lt k)
{
lt res=1;
while(k>0){
if(k&1) res*=a;
a*=a; k>>=1;
}
return res;
}
lt DP(lt k,int ll,int rr,int d)
{
if(dp[k][ll][rr]) return dp[k][ll][rr];
lt tpow=qpow(2,k);
if(ll==rr) return a[d][ll]*tpow;
return dp[k][ll][rr]=max(DP(k+1,ll+1,rr,d)+a[d][ll]*tpow,DP(k+1,ll,rr-1,d)+a[d][rr]*tpow);
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
a[i][j]=read();
for(int i=1;i<=n;++i)
{
memset(dp,0,sizeof(dp));
ans+=DP(1,1,m,i);
}
print(ans);
return 0;
}