[NOIP2007]矩阵取数游戏(详细题解、含多种思路)

题目

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

  1. 每次取数时须从每行各取走一个元素,共 n 个。经过 m 次后取完矩阵内所有元素;
  2. 每次取走的各个元素只能是该元素所在行的行首或行尾;
  3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值 ×2i,其中 i 表示第 i 次取数(从 1 开始编号);
  4. 游戏结束总得分为 m 次取数得分之和。

帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。

输入 #1

2 3
1 2 3
3 4 2

输出 #1

82

数据范围:
60% 的数据满足:1≤n,m≤30,答案不超过 1016
100% 的数据满足:1≤n,m≤80,0≤ai,j≤10000。(高精预警)

分析

首先看出,每行的问题是独立的、互不影响,可以对每一行分别求解最高分,相加得出整个游戏的最高分。

就每一行而言,取数的顺序是有讲究的,先取的数的倍数较少,后取的数的倍数较大,因此要找到最优的取数方案。有几种常见算法:穷举、贪心、dp。

  1. 因为n比较大,穷举带来的2n复杂度不可接受。
  2. 贪心(每次取两端中较小者)也不对,可找一个反例,100、100、1、100,贪心的取法是100、100、1、100,答案为2208,最优取法是100(右手第一个)、1、100、100,答案为2604,贪心输了。本质上,只要贪心的取法不能满足全局从小到大(该规律可能只适用于这道题),就不一定能得到最优解。
  3. 只剩动规了。

问题是怎么设计动规的状态,满足最优子结构性质和无后效性原则?

我们设计动规的状态时,常设置状态为选取了前i个数,但这题的规则是每次从开头或者末尾取,这是差异,那怎么调整呢?应该回到动规性质上来考虑,状态设置的要求是无后效性,即之前的选择不影响之后的选择,当前的选择是过去的完整总结。不妨设想我们玩这个游戏玩到某一步时,我们已从行首取了3个数,从行尾取了5个数,还有中间10个数可以取,那接下来的游戏都是在这10个数中进行,跟之前的前3个、后5个已经没有关系了。这么思考很容易设计出:f[i][j]表示选取了前i个数和后j个数。这里要注意的是,题目规则中的2阶乘加权是由取数的轮次决定的,这个次数只与i和j相关,不受之前所取数的影响,因此这个状态满足无后效性原则。又因为分数是一直简单累加的,所以当前最优解必然促成全局最优解,满足最优子结构性质。

状态转移比较容易构造,f[i][j]由f[i-1][j]或f[i][j-1]转移而来,分别意味着选取了a[i]和选取了a[m+1-j]。

f[i][j]=max(2i+j*a[i] + f[i-1][j], 2i+j*a[m+1-j]+f[i][j-1]) i,j>=0 i+j<=m

初始状态:
f[0][0]=0

目标状态和结果:
ans=max{f[i][j] | i+j=m}

注意迭代的顺序,要按选取数量从小到大的顺序进行迭代,i、j循环须按从小到大顺序。

最后的问题就是,数据范围比较大,答案会超过int64范围,需要高精度计算(本赛题的难度之一就是这个了,需要压位存储)。 可以通过套模板或者用原生支持高精度的

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值