Luogu P1005 矩阵取数游戏

Description:

帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n×m的矩阵,矩阵中的每个元素a_i,j均为非负整数。游戏规则如下:

  1. 每次取数时须从每行各取走一个元素,共nn个。经过mm次后取完矩阵内所有元素;
  2. 每次取走的各个元素只能是该元素所在行的行首或行尾;
  3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值×2^i ,其中i表示第i次取数(从1开始编号);
    游戏结束总得分为m次取数得分之和。
    帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。

Analysis:

贪心不行:如果有一组数据是4,3,10,1,1,1,1,1,1,1,1,5,5,5,5,9贪心就是错的,会先把5取完,然而应该先取1。
前面的状态对后面有影响,这已经失去了贪心的条件。
DP:区间变为[i,j]时的最大得分
上一次可以从i-1取,也可以从j+1取,所以 f[i][j] 由 f[i-1][j] 和 f[i][j+1] 转移来。
f[i][j] = max( f[i-1][j] + a[i-1]×2^g ,f[i][j+1] + a[j+1]×2^g )
g表示第几次,g = m-j+i-1,即取走元素的个数。

Code

#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const int MAX_N = 81;
ll a[MAX_N],f[MAX_N][MAX_N],p[MAX_N],n,m,ans;
void solve()
{
	memset(f,0,sizeof(f));
	for(int i = 1;i <= m;++i)
	{
		for(int j = m;j >= i;--j)
		{
			f[i][j] = max(f[i-1][j] + a[i-1]*p[m-j+i-1],f[i][j+1] + a[j+1]*p[m-j+i-1]);
		}
	}
	ll maxn = 0;
	for(int i = 1;i <= m;++i) maxn = max(maxn,f[i][i] + a[i]*p[m]);
	ans += maxn;
}
int main()
{
	scanf("%lld%lld",&n,&m);
	p[0] = 1;
	for(int i = 1;i <= 64;++i) p[i] = p[i-1] << 1;
	for(int i = 1;i <= n;++i)
	{
		for(int j = 1;j <= m;++j)	scanf("%lld",&a[j]);	
		solve();
	}
	printf("%lld
",ans);
	return 0;
}
岂能尽如人意,但求无愧我心
原文地址:https://www.cnblogs.com/Zforw/p/11298821.html