由於上方和右上方都要打掉才能打這個位置,因此從第一行往下枚舉不能得到正確答案,所以考慮倒序枚舉,從最後一列按行枚舉ios
具體註釋看代碼ide
#include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #include<vector> #include<string> #include<cstring> #include<map> using namespace std; typedef long long ll; const int N=55; int n; int m; int a[N][N]; int f[N][N][N*(N+1)/2+1]; int main(){ cin>>n>>m; memset(f,-0x3f,sizeof f); int i,j,k,l; f[n+1][0][0]=0; //只有這個位置是初始合法轉移位置 for(i=1;i<=n;i++) for(j=1;j<=n-i+1;j++) cin>>a[i][j]; for(i=n;i>=1;i--){ //從最後一列往前枚舉 int sum=0; for(j=0;j<=n-i+1;j++){ //0表明這一列不打,最多能夠打到n-i+1行 sum+=a[j][i]; //前綴和 for(k=j;k<=m;k++){ //至少要從j開始,最多打m個 for(l=max(0,j-1);l<=n-i;l++){ //由於右上方必需要打,因此至少是j-1,最多枚舉到前一列的最後一行 f[i][j][k]=max(f[i][j][k],f[i+1][l][k-j]+sum); } } } } int ans=0; for(i=1;i<=n;i++){ for(j=0;j<=n-i+1;j++){ ans=max(ans,f[i][j][m]); } } cout<<ans<<endl; }