Description
要打掉一个砖块必须打掉他左上及右上的两个砖块,砖块有得分,问打掉 \(m\) 个获得的最大得分。
\(1\leqslant n\leqslant 50\)
Solution
最后打掉的一定是每列选一个前缀:
2 2 3 4
8 2 7
2 3
49
发现可以前缀和优化。
Code
#include<bits/stdc++.h>
using namespace std;
int n,m;
#define MAXN 51
int a[MAXN][MAXN];
int c[MAXN][MAXN];
int f[MAXN][MAXN][MAXN * MAXN];
int pre[MAXN][MAXN][MAXN * MAXN];
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++i)for(int j = 1;j <= n - i + 1;++j)scanf("%d",&a[i][j]);
for(int i = 1;i <= n;++i)for(int j = 1;j <= n - i + 1;++j)c[i][j] = c[i - 1][j] + a[i][j];
for(int j = 1;j <= n;++j)
{
for(int k = 0;k <= m;++k)pre[0][j - 1][k] = f[0][j - 1][k];
for(int i = 1;i <= n - j + 2;++i)
{
for(int k = 0;k <= m;++k)
{
pre[i][j - 1][k] = max(pre[i - 1][j - 1][k],f[i][j - 1][k]);
}
}
for(int i = 0;i <= n - j + 1;++i)
{
for(int k = i;k <= m;++k)
{
f[i][j][k] = max(f[i][j][k],pre[i + 1][j - 1][k - i] + c[i][j]);
}
}
}
int ans = max(f[1][n][m],f[0][n][m]);
cout << ans << endl;
return 0;
}