noip动态规划总结

 

难点:模型的建立和理解。

要求:对于每道题,都能在很短的时间里把思路完整地整理一遍,可以快速而无误的写出程序。

(一) 两种动机

a) 利用重叠子问题,进行记忆化求解,即利用递归。

例1、 括号序列

分析:d[I,j]:=min

也可以用记忆化搜索。

需要的只有方程和边界。

例2、 棋盘分割[noi99]

目标式变形:

因为不变,所以要使每个矩阵的平方和尽量小。

F[k,x1,y1,x2,y2]为切k刀成为(x1,y1)-(x2,y2)的矩形的平方和的最小值。

F[k,x1,y1,x2,y2]:=

例3、 决斗[poi]

转换模型:若一人可以赢得比赛,只有自己能和自己做战时。

meet[i,j]记录ij是否能相遇。当ij相遇时,只有i能和k相遇,k能和j相遇,并且k可以被ij打败。

Meet[I,j]=

b) 把问题看作是多阶段决策过程。

例4、 舞蹈家怀特先生

对于一个状态,为了让它没有后效性,则必须记两个值,右脚的位置 and 左脚的位置。

无后效性是应用动态规划的重要条件。如果不满足无效后性,那么状态表示是不合理的,因为同一个状态可能对应很多本质不同的实例。

所以f[i]的状态不合理,f[I]àf[I,j]àf[I,j,k]

c) 总结及基本概念

J 无后效性和子结构: 本质相同,利用无后效性定义状态,利用最优子结构进行转移。状态和状态转移是动规的精髓。

J 状态表示和状态转移: 核心。消除后效性可以通过增加维数来实施,也可以在保持无后效性的情况下改变状态定义。但是有可能使子问题不重复,达不到效果。

J 两种实现方式:递推和记忆化搜索。递归很灵活,记忆化搜索教好写,并可以避免无用的状态,但是很难用到滚动数组来优化。

1 经典的方程f[i]:=max(f[j]+1)   a[i]< or > a[j]

a) 直接做o(n2)

b) 加上树状数组,有时需要离散化,较容易理解,可以直接更新,应用范围有局限性。复杂度o(nlogn)

c) 二分优化

这种方法不好理解,但是适用性较强。

主体

Procedure;

Begin

L:=0;r:=ee;

While l<r do

Begin

      Mid:=(l+r+1) shr 1;

      If yes(需要量情况而定,并且要注意是找第一大于等于,或是大于,或是小于,或是小于等于的) then r:=mid-1 else l:=mid;

End;

If l=ee then inc(ee);

Inc(l);b[l]:=a[i];

End;

最后的ee就是答案,而事实上如果要记下每一长度的所有的能够得到的值也十分方便,还可以略掉中间值相同的。

例题:求一个序列的最长下降序列,并输出不同的方案。

分析:首先对于前面的值若和后面的一样,那么一定取后面的更优,所以最主要的是去掉相等的值。

主体

在上一段后加上

Procedure

Begin

Next[i]:=top[l];top[l]:=I;

While a[next[i]]=a[i] do next[i]:=next[next[i]];

J:=top[l-1];

While a[j]<=a[i] do

Begin

     G[i]:=g[i]+g[j];j:=next[j];

End;

If g[i]=0 then g[i]:=0;

End;

这里还需要a[n+1]=-maxlongint,这样方案数就直接是g[n+1].

2 分段的动规,有的时候,动规的两段之间没有什么关系,这时就可以分段地动规。

例   矩阵取数问题(noip2007

对于一个n*m的矩阵,取m次,每次只能取行首和行末的,每次的分值就是每格的分值乘上2i的和。

分析   因为行的取的状态互不干扰,所以每一行一行的讨论。

这里用的是区间动规,并不是很明显,需要分析。区间动规一般不太明显的。

3 双线程动规

例   传纸条

从矩阵的(1,1)开始,走两条不重合的路径,使得总和最大。

分析   因为有两条路径,所以使其同时出发,建一个四维的方程。

F[I1,j1,i2,j2],状态转移从上和左转移过来。但是f[I,j,I,j]=-maxlongint


 

4 一些模型

a) 线性动规

i. F[i]={f[j]+?}   i<j

例   尼克的任务  

尼克需要完成一些任务,一开始就不能停止,问获得的最大空闲时间。

分析   显然这样推下来,但是由于一旦开始就不能停止,所以需要注意的是要从后往前推,因为若处于开始时间,就不能从i+1推到前面来,只能从en[i]推出来。

ii. 有二维的f[I,j]=max{f[i-1,jj]+?}

这种方程便可以滚动优化空间,例如最经典的背包,这种方程用得较多。如书的复制、多米诺骨牌。

iii. 这种线性动规经常会有后效性,这时就需要加维来剪掉后效性。

b) 串动规

i. 会用到串匹配的性质,会有点难,如加上kmp之类的优化。

c) 判定性动规

i. 这一类的动规只需要写上是否存在,一般难以想到,有时可以将答案比较小的动规变成判定性动规来写。

d) 区间动规

i. F[I,j]={f[ii,jj]+?}  

有时会在串动规中用到。

e) 状态压缩动规

i. 有点难度,但是一看数据范围容易想到。转移一般是用记忆化搜索。

例   平板涂色

一种板,分成了不同的区域,涂一种颜色之前,需要将其上面的涂完,问最多拿多少次刷子。

分析   因为矩形个数<=16,所以很快想到状态压缩动态规划。

例   单词游戏

单词首尾相连,使得长度最长。

分析   再次发现一个很好的东西,单词数<=16就不用说了吧!!

ii. 但是这里必须要注意判断状态的合理性。

f) 树型动规

i. 一些根本不像树规的树规

例   电报公司

给一串字符串中的字母给三进制的数,使其不重复,求最小长度。

分析   因为最多就只有m层,所以在底下时实际上是一棵树。

F[d,I,j]=min{f[d-1,I,jj]+f[d-1,jj+1,kk]+f[d-1,kk+1,j]+s[j]-s[i-1]}(每一层长度+1

ii. 一些特像树规的树规

有时候可以当作贪心来做。

iii. 和其它动规混在一起。

iv. 树规的实现

1. 边权的问题

例   在一棵树里,需要选一些节点,但是它连向根节点的边都要选,求出在这棵树中取k个根节点,使得点权-边权最大。

分析   方程十分简单

F[I,j]表示i中取j个的最大值,

F[I,j]=max(f[i1,j1]+f[i2,j2]+f[i3,j3]+…+f[In,jn]-va)

但是,转移起来可能有点儿麻烦,一般用搜索做,当然,拓扑也是可以的。

因为每一层相当于背包,最大值实际上就是f[I,j]=g[n,j]表示前n个背包中重量为j时的最大值。G[n,j]=max{g[n-1,j],g[n-1,j-k]+f[in,k]-va[in]}

所以直接按顺序做,加一个滚动数组(实际上是downto)优化空间。G[n,0]肯定为0

2. 点值的问题

例   没有上司的晚会,选一些点,并且它选了后儿子就不能选了,求最大值。

分析   这个可以贪心直接做,背包反而麻烦了。因为边上的权值没有,所以可以转为二叉树。只是要注意右儿子状态。

3. 有依赖的背包问题

例   选课

一些课有先修课,选择m门课,使得在满足条件的基础上,点值总和最大。

分析 和上一题差不多。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值