NOI2005瑰丽的华尔兹

p { margin-bottom: 0.21cm; }

一道经典的用单调性优化的动态规划问题。

题意简述:
1900开始在一个N*M的矩阵第X行第Y列处,第k个时间段内他可以向方向dk走最多tk个格子(也可以不走),不能走出边界,不能碰到家具,求最长能走的距离。

朴素动态规划:
很容易得出状态和转移方程:
状态:f[k,i,j]表示第k个时间段过完后,1900走到了第i行第j列,前k个时间段1900最长能行走的距离。
转移方程(以di=2时为例,其他情况类似):f[k,i,j]=max{f[k-1,i',j]+i-i'},i'<i,i-i'<=tk且(i',j)~(i,j)之间没有家具。
初始状态f[0,X,Y]=0
时间复杂度O(NMT)

单调性优化:
在求解第j列的状态f[k,1..N,j]时,令g[i]=f[k-1,i,j]-i,则f[k,i,j]=max{g[i']}+i,i'<i,i-i'<=tk且(i',j)~(i,j)之间没有家具。注意到g[i']只与f[k-1,i',j]和i'值有关,而对于状态f[k,i,j],所有合法的g[i']只要加上一个相等的值i都可以转移到它。所以实际上状态转移时是在寻找所有合法的g[i']值中最大的。此时,问题转化为在第j列中对每行求解“以第i行的元素为末尾的长度位ti的连续段中g函数的最大值”。即对所有的i求解max{g[i-tk+1..i]}。
现在我们按照i值递增的顺序来求解max{g[i-tk+1..i]}。用一个单调队列维护g[i],队列中i值递增而g[i]值递减。在求解max{g[i-tk+1..i]}时,先不断检查队首元素,如果被检查的队首元素与当前格子(i,j)的距离超过了tk,就意味着此元素不仅对于当前状态不合法,而且对于以后拥有更大的i的状态也不合法,于是将其删除并继续检查;否则队首元素的g函数值就是当前要求的状态的值。再不断检查队尾元素,如果被检查的队尾元素的g函数值小于或等于g[i],对于以后更大的i,此元素不可能优于g[i],将其删除;否则将g[i]插入队尾。
在对第j列的求解过程中,每个元素最多进队一次,出队一次。求每个状态时都要返回一次队首元素的值。所以复杂度是O(N)的。决策均摊时间复杂度就为O(1)。总时间复杂度为O(NMK)。

在实现时,我把g函数改成了二维,方便对各种情况进行统一操作。

 

 

开始测试 Ambusher
   正在编译 Ambusher.adv1900 ...成功
      正在测试 Ambusher.adv1900.1(adv19001.in)... 正确 0.005秒 得分: 10
      正在测试 Ambusher.adv1900.2(adv19002.in)... 正确 0.003秒 得分: 10
      正在测试 Ambusher.adv1900.3(adv19003.in)... 正确 0.003秒 得分: 10
      正在测试 Ambusher.adv1900.4(adv19004.in)... 正确 0.030秒 得分: 10
      正在测试 Ambusher.adv1900.5(adv19005.in)... 正确 0.269秒 得分: 10
      正在测试 Ambusher.adv1900.6(adv19006.in)... 正确 0.391秒 得分: 10
      正在测试 Ambusher.adv1900.7(adv19007.in)... 正确 0.203秒 得分: 10
      正在测试 Ambusher.adv1900.8(adv19008.in)... 正确 0.465秒 得分: 10
      正在测试 Ambusher.adv1900.9(adv19009.in)... 正确 0.472秒 得分: 10
      正在测试 Ambusher.adv1900.10(adv190010.in)... 正确 0.445秒 得分: 10
      Ambusher.adv1900 的总分: 100
   Ambusher 的总分: 100


























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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值