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;
}
 posted on 2020-09-15 08:56  15101051  阅读(94)  评论(0编辑  收藏  举报