导航:首页 > 源码编译 > 动态规划水算法题

动态规划水算法题

发布时间:2022-12-06 11:45:22

算法题套路总结(三)——动态规划

前两篇我总结了链表和二分查找题目的一些套路,这篇文章来讲讲动态规划。动态规划从我高中开始参加NOIP起就一直是令我比较害怕的题型,除了能一眼看出来转移方程的题目,大部分动态规划都不太会做。加上后来ACM更为令人头秃的动态规划,很多题解看了之后,我根本就不相信自己能够想出来这种解法,看着大佬们谈笑间还加一些常数优化,一度怀疑自己的智商。以前一直觉得动态规划是给大佬准备的,所以刻意地没有去攻克它,主要也是没有信心。但是后来慢慢的,我再做LC的时候,发现很多DP的题目我自己慢慢能够推出转移方程了,而且似乎也没那么难。我一直在思考,到底是我变强了,还是因为LC的题目相比ACM或者NOI太简单了。其实主要还是后者,但是同时我也发现,动态规划其实是有套路的,我以前方法不对,总结太少。
主要就是,站在出题人的角度,他几乎不太可能完全凭空想出一个新的DP模型,因为动态规划毕竟要满足:

因此,能够利用DP来解决的问题实际上是有限的,大部分题目都是针对现有的模型的一些变种,改改题目描述,或者加点限制条件。所以要想攻克DP题目,最根本的就是要充分理解几个常见的DP模型。而要充分理解常见经典DP模型,就需要通过大量的做题和总结,而且二者不可偏废。通过做题进行思考和量的积累,通过总结加深理解和融会贯通进而完成质的提升。

动态规划是求解一个最优化问题,而最核心的思想就是:

解一道DP题目,先问自己几个问题:

当然以上内容看起来比较抽象,虽然它深刻地揭露了动态规划的本质,但是如果临场要去想明白这些问题,还是有些难度。如果只是针对比赛和面试,就像前面说的,DP题型是有限的。只要刷的题目足够多,总结出几个经典模型,剩下的都是些变种+优化而已。

一般来说,动态规划可以分成4个大类:

线性DP就是阶段非常线性直观的模型,比如:最长(上升|下降)序列,最长公共子序列(LCS)等,也有一些简单的递推,甚至都算不上是 经典模型

最长上升序列是一个非常经典的线性模型。说它是个模型,是因为它是一类题的代表,很多题目都只是换个说法,或者要求在这基础上进一步优化而已。最长上升序列最基础的转移方程就是 f[i] = max{f[j]}+1 (a[i] > a[j]) , f[i] 表示一定要以 a[i] 结尾的序列,最长长度是多少。很显然就是在前面找到一个最大的 f[j] 同时满足 a[j]<a[i] 。因此是 N^2 的时间复杂度和N的空间复杂度。这种方法是最朴素直观的,一定要理解。它非常简单,因此很少有题目直接能够这么做。大部分相关题目需要进一步优化,也就是有名的单调队列优化,能够把复杂度优化到nlogn。

说单调队列优化之前必须明白一个贪心策略。因为要求的是最长上升序列,那么很显然长度为k的上升序列的最大值(最后一个数)越小越好,这样后面的数才有更大的概率比它大。如果我们记录下来不同长度的上升序列的最后一个数能达到的最小值,那么对于后续每个数t,它要么能放到某个长度为y的序列之后,组成长度为y+1的上升序列,要么放到某个长度为x的序列后面,把长度为x+1的序列的最大值替换成t。同时我们可以发现,如果x<y,那么长度为x序列的最后一个数一定比长度为y的序列最后一个数小。因此这个上升序列我们可以用一个数组来维护(所谓的单调队列),数组下标就代表序列长度。 opt[i]=t 表示长度为i的上升序列最后一个数最小是t。那么当我们在面对后续某个数x时,可以对单调队列opt进行二分,把它插到对应的位置。因此总体复杂度就是NlogN。
相关题目比如:

但是你可以发现,其实这个题型其实变种很有限,吃透了也就那么回事。所以一定要总结。

最长公共子序列也是线性DP中的一种比较常见的模型。说它是一种“模型”其实有点拔高了,其实它就是一类比较常见的题目。很多题目都是在LCS的基础上进行简单的扩展,或者仅仅就是换一个说法而已。
求两个数组的最长公共子序列,最直观地做法就是:设f[i][j]表示S[..i]和T[..j]的最长公共子序列,则有:

这个转移方程也非常好理解,时间复杂度是 N^2 ,空间复杂度也是 N^2 。不过仔细观察你可以发现,当我们计算第i行时只与i-1和i行有关。因此我们可以利用01滚动来优化空间复杂度为2N。
相关题目:

线性DP除了上述的两种常见题型,还有很多别的类型,包括背包。我们要努力去尝试理解这些题目的异同,它们的转移方程,以及思路,可能的变化,这样才能更好的应对未知的题目。以下是一些我总结的题型:

最终结果就是max(0, f[n][2]+f[n][4])。
不过实际上你可以发现,由于各个状态只和前一维有关,且只能由固定的一个状态转移过来,因此我们可以省掉一维,只用4个变量来存储:

剩下的,同123题类似,由于最多进行k次交易,那么一天就有2k个状态:第1次买/卖……第k次买/卖,结合123题的优化,我们只需要2k个变量就能存储这些状态。因此设f[i×2]为第i次买入的最优值,f[i×2+1]为第i次卖出的最优值:

以上都是对一些常见的线性DP的一些小结,实际上线性DP还有一个重要的题型就是背包。关于背包,有很多相关的讲解,我这里就不多说了,推荐大家看看 背包九讲 。下一章依然是DP专题,我讲总结一些区间DP的题型。大部分区间DP都是hard级的,对于希望提高自己水平的人来说,需要投入更多精力去理解。

Ⅱ 动态规划算法建模,3 名商人各带 1 名随从乘船渡河问题

①1商人1仆人坐船 商人乘船回
②商人下船 2仆人坐船 1仆人乘船回
③仆人下船 2商人坐船 1商人1仆人乘船回
④仆人下船 2商人坐船 1仆人乘船回
至此3个商人全部到达河对岸 让1仆人把剩下两个仆人拉过对岸来就好了。。

Ⅲ 动态规划算法的题目(急)

给出个思路吧:
阶段变量i:1~n门课程
状态变量h:已经用掉的小时数h
决策变量dh:下一门课程分配的小时数dh
目标函数sum_f:已经在前i门课上取得的总成绩sum_f
状态转移方程:sum_f(i+1)=sum_f(i)+f(i+1)
顺时序递推计算即可.

Ⅳ 1、 用动态规划方法求下述问题的最优解:Max z=x1x2x3x4 2x1+3x2+x3+2x4=11Xj≥0且为整数

偶形式: 2y1-y2-y3=-2 3y1-2y2-3y3=-4 求 max -24y1+10y2+15y3 优解 y1=0,y2=2,y3=0 优值20设原始问题min{cx|Ax=bx≥0}则其偶问题 max{yb|yA≤c}。

原问题引入人工变量x4,剩余变量x5,人工变量x6 。

maxz=2x1+3x2-5x3 -mx4-mx6、x1+x2+x3+x4=7,2x1-5x2+x3-x5+x6=10,x1,x2,x3,x4,x5,x6≥0用人工变量法求解。

大m法:先化成标准形

max z'=-2x1-3x2-x3+0x4+0x5-Mx6-Mx7

s.t. x1+4x2+2x3-x4+x6=4

3x1+2x2-x5+x7=6

x1 x2 x3 x4 x5 x6 x7≥0

最优解 X=(4/5,9/5,0,0,0,0)

Z最优值 min z=7

非基变量x3的检验数等于0,所以有无穷多最优解

两阶段法:第一阶段最优解X=(4/5,9/5,0,0,0,0)是基本可行解 min z=0

第二阶段最优解 X=(4/5,9/5,0,0,0,0) min z=7

非基变量x3的检验数为0,所以有无穷多最优解

(4)动态规划水算法题扩展阅读:

动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。

若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。我们可以用一个表来记录所有已解的子问题的答案。

Ⅳ 动态规划算法程序例子

给你导弹拦截的吧:
[问题描述]
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数,每个数据之间至少有一个空格),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

[输入输出样例]
INPUT:
389 207 155 300 299 170 158 65
OUTPUT:
6(最多能拦截的导弹数)
2(要拦截所有导弹最少要配备的系统数)

[问题分析]
我们先解决第一问。一套系统最多能拦多少导弹,跟它最后拦截的导弹高度有很大关系。假设a[i]表示拦截的最后一枚导弹是第i枚时,系统能拦得的最大导弹数。例如,样例中a[5]=3,表示:如果系统拦截的最后一枚导弹是299的话,最多可以拦截第1枚(389)、第4枚(300)、第5枚(299)三枚导弹。显然,a[1]~a[8]中的最大值就是第一问的答案。关键是怎样求得a[1]~a[8]。
假设现在已经求得a[1]~a[7](注:在动态规划中,这样的假设往往是很必要的),那么怎样求a[8]呢?a[8]要求系统拦截的最后1枚导弹必须是65,也就意味着倒数第2枚被拦截的导弹高度必须不小于65,则符合要求的导弹有389、207、155、300、299、170、158。假如最后第二枚导弹是300,则a[8]=a[4]+1;假如倒数第2枚导弹是299,则a[8]=a[5]+1;类似地,a[8]还可能是a[1]+1、a[2]+1、……。当然,我们现在求得是以65结尾的最多导弹数目,因此a[8]要取所有可能值的最大值,即a[8]=max{a[1]+1,a[2]+1,……,a[7]+1}=max{a[i]}+1 (i=1..7)。
类似地,我们可以假设a[1]~a[6]为已知,来求得a[7]。同样,a[6]、a[5]、a[4]、a[3]、a[2]也是类似求法,而a[1]就是1,即如果系统拦截的最后1枚导弹是389,则只能拦截第1枚。
这样,求解过程可以用下列式子归纳:
a[1]=1
a[i]=max{a[j]}+1 (i>1,j=1,2,…,i-1,且j同时要满足:a[j]>=a[i])
最后,只需把a[1]~a[8]中的最大值输出即可。这就是第一问的解法,这种解题方法就称为“动态规划”。

第二问比较有意思。由于它紧接着第一问,所以很容易受前面的影响,多次采用第一问的办法,然后得出总次数,其实这是不对的。要举反例并不难,比如长为7的高度序列“7 5 4 1 6 3 2”, 最长不上升序列为“7 5 4 3 2”,用多次求最长不上升序列的结果为3套系统;但其实只要2套,分别击落“7 5 4 1”与“6 3 2”。所以不能用“动态规划”做,那么,正确的做法又是什么呢?
我们的目标是用最少的系统击落所有导弹,至于系统之间怎么分配导弹数目则无关紧要,上面错误的想法正是承袭了“一套系统尽量多拦截导弹”的思维定势,忽视了最优解中各个系统拦截数较为平均的情况,本质上是一种贪心算法,但贪心的策略不对。如果从每套系统拦截的导弹方面来想行不通的话,我们就应该换一个思路,从拦截某个导弹所选的系统入手。
题目告诉我们,已有系统目前的瞄准高度必须不低于来犯导弹高度,所以,当已有的系统均无法拦截该导弹时,就不得不启用新系统。如果已有系统中有一个能拦截该导弹,我们是应该继续使用它,还是另起炉灶呢?事实是:无论用哪套系统,只要拦截了这枚导弹,那么系统的瞄准高度就等于导弹高度,这一点对旧的或新的系统都适用。而新系统能拦截的导弹高度最高,即新系统的性能优于任意一套已使用的系统。既然如此,我们当然应该选择已有的系统。如果已有系统中有多个可以拦截该导弹,究竟选哪一个呢?当前瞄准高度较高的系统的“潜力”较大,而瞄准高度较低的系统则不同,它能打下的导弹别的系统也能打下,它够不到的导弹却未必是别的系统所够不到的。所以,当有多个系统供选择时,要选瞄准高度最低的使用,当然瞄准高度同时也要大于等于来犯导弹高度。
解题时用一个数组sys记下当前已有系统的各个当前瞄准高度,该数组中实际元素的个数就是第二问的解答。

[参考程序]
program noip1999_2;
const max=1000;
var i,j,current,maxlong,minheight,select,tail,total:longint;
height,longest,sys:array [1..max] of longint;
line:string;
begin
write('Input test data:');
readln(line); {输入用字符串}
i:=1;
total:=0; {飞来的导弹数}
while i<=length(line) do {分解出若干个数,存储在height数组中}
begin
while (i<=length(line)) and (line[i]=' ') do i:=i+1; {过滤空格}
current:=0; {记录一个导弹的高度}
while (i<=length(line)) and (line[i]<>' ') do {将一个字符串变成数}
begin
current:=current*10+ord(line[i])-ord('0');
i:=i+1
end;
total:=total+1;
height[total]:=current {存储在height中}
end;
longest[1]:=1; {以下用动态规划求第一问}
for i:=2 to total do
begin
maxlong:=1;
for j:=1 to i-1 do
begin
if height[i]<=height[j]
then if longest[j]+1>maxlong
then maxlong:=longest[j]+1;
longest[i]:=maxlong {以第i个导弹为结束,能拦截的最多导弹数}
end;
end;
maxlong:=longest[1];
for i:=2 to total do
if longest[i]>maxlong then maxlong:=longest[i];
writeln(maxlong); {输出第一问的结果}
sys[1]:=height[1]; {以下求第二问}
tail:=1; {数组下标,最后也就是所需系统数}
for i:=2 to total do
begin
minheight:=maxint;
for j:=1 to tail do {找一套最适合的系统}
if sys[j]>height[i] then
if sys[j]<minheight then
begin minheight:=sys[j]; select:=j end;
if minheight=maxint {开一套新系统}
then begin tail:=tail+1; sys[tail]:=height[i] end
else sys[select]:=height[i]
end;
writeln(tail)
end.

[部分测试数据]
输入1:300 250 275 252 200 138 245
输出1:
5
2

输入2:181 205 471 782 1033 1058 1111
输出2:
1
7

输入3:465 978 486 476 324 575 384 278 214 657 218 445 123
输出3:
7
4

输入4:236 865 858 565 545 445 455 656 844 735 638 652 659 714 845
输出4:
6
7
够详细的吧

Ⅵ 问一道动态规划算法题. 设A和B是长度相等,长度为n的字符串. 他们的最长公共子串长度为(n-L)

最长公共子序列(Longest-Common-Subsequence,LCS)
dp[i][j]:dp[i][j]表示长度分别为i和j的序列X和序列Y构成的LCS的长度
dp[i][j] = 0,如果i=0 或 j=0
dp[i][j] = dp[i-1][j-1] + 1,如果 X[i-1] = Y[i-1]
dp[i][j] = max{ dp[i-1][j], dp[i][j-1] },如果 X[i-1] != Y[i-1]
LCS长度为 dp[Xlen][Ylen]

Ⅶ 动态规划法的原理

动态规划法[dynamic programming method (DP)]是系统分析中一种常用的方法。在水资源规划中,往往涉及到地表水库调度、水资源量的合理分配、优化调度等问题,而这些问题又可概化为多阶段决策过程问题。动态规划法是解决此类问题的有效方法。动态规划法是20世纪50年代由贝尔曼(R. Bellman)等人提出,用来解决多阶段决策过程问题的一种最优化方法。所谓多阶段决策过程,就是把研究问题分成若干个相互联系的阶段,由每个阶段都作出决策,从而使整个过程达到最优化。许多实际问题利用动态规划法处理,常比线性规划法更为有效,特别是对于那些离散型问题。实际上,动态规划法就是分多阶段进行决策,其基本思路是:按时空特点将复杂问题划分为相互联系的若干个阶段,在选定系统行进方向之后,逆着这个行进方向,从终点向始点计算,逐次对每个阶段寻找某种决策,使整个过程达到最优,故又称为逆序决策过程。
[1]动态规划的基本思想
前文主要介绍了动态规划的一些理论依据,我们将前文所说的具有明显的阶段划分和状态转移方程的动态规划称为标准动态规划,这种标准动态规划是在研究多阶段决策问题时推导出来的,适合用于理论上的分析。在实际应用中,许多问题的阶段划分并不明显,这时如果刻意地划分阶段法反而麻烦。一般来说,只要该问题可以划分成规模更小的子问题,并且原问题的最优解中包含了子问题的最优解(即满足最优子化原理),则可以考虑用动态规划解决。
动态规划的实质是分治思想和解决冗余,因此,动态规划是一种将问题实例分解为更小的、相似的子问题,并存储子问题的解而避免计算重复的子问题,以解决最优化问题的算法策略。
由此可知,动态规划法与分治法和贪心法类似,它们都是将问题实例归纳为更小的、相似的子问题,并通过求解子问题产生一个全局最优解。其中贪心法的当前选择可能要依赖已经作出的所有选择,但不依赖于有待于做出的选择和子问题。因此贪心法自顶向下,一步一步地作出贪心选择;而分治法中的各个子问题是独立的(即不包含公共的子子问题),因此一旦递归地求出各子问题的解后,便可自下而上地将子问题的解合并成问题的解。但不足的是,如果当前选择可能要依赖子问题的解时,则难以通过局部的贪心策略达到全局最优解;如果各子问题是不独立的,则分治法要做许多不必要的工作,重复地解公共的子问题。
解决上述问题的办法是利用动态规划。该方法主要应用于最优化问题,这类问题会有多种可能的解,每个解都有一个值,而动态规划找出其中最优(最大或最小)值的解。若存在若干个取最优值的解的话,它只取其中的一个。但是首先要保证该问题的无后效性,即无论当前取哪个解,对后面的子问题都没有影响.在求解过程中,该方法也是通过求解局部子问题的解达到全局最优解,但与分治法和贪心法不同的是,动态规划允许这些子问题不独立,(亦即各子问题可包含公共的子子问题)也允许其通过自身子问题的解作出选择,该方法对每一个子问题只解一次,并将结果保存起来,避免每次碰到时都要重复计算。
因此,动态规划法所针对的问题有一个显着的特征,即它所对应的子问题树中的子问题呈现大量的重复。动态规划法的关键就在于,对于重复出现的子问题,只在第一次遇到时加以求解,并把答案保存起来,让以后再遇到时直接引用,不必重新求解。
3、动态规划算法的基本步骤
设计一个标准的动态规划算法,通常可按以下几个步骤进行:
(1)划分阶段:按照问题的时间或空间特征,把问题分为若干个阶段。注意这若干个阶段一定要是有序的或者是可排序的(即无后向性),否则问题就无法用动态规划求解。
(2)选择状态:将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示出来。当然,状态的选择要满足无后效性。

Ⅷ 动态规划算法详解

动态规划一般也只能应用于有最优子结构的问题。最优子结构的意思是局部最优解能决定全局最优解(对有些问题这个要求并不能完全满足,故有时需要引入一定的近似)。简单地说,问题能够分解成子问题来解决。

将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解(这部分与分治法相似)。与分治法不同的是,适合于用动态规划求解的问题,经分解得到的子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。通常可以用一个表来记录所有已解的子问题的答案。

问题的一个最优解中所包含的子问题的解也是最优的。总问题包含很多个子问题,而这些子问题的解也是最优的。

用递归算法对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,从而获得较高的效率。

:很显然,这道题的对应的数学表达式是

其中F(1)=1, F(2)=2。很自然的状况是,采用递归函数来求解:

参考:
http://blog.csdn.net/zmazon/article/details/8247015
http://blog.csdn.net/lisonglisonglisong/article/details/41548557
http://blog.csdn.net/v_JULY_v/article/details/6110269
http://blog.csdn.net/trochiluses/article/details/37966729

Ⅸ 动态规划算法(pascal)

在计算够不够开销时
20%这个数据是废的
你可以先减去预算再考虑存多少钱
比如手头钱的数目为a
预算为b
存在妈妈处的钱为c
可以先从a中减去b
然后c就等于c+a
div
100
*100
var

begin
a:=0;
c:=0;
bo:=true;
for
i:=1
to
12
do
begin
read(b[i]);
inc(a,300);
if
a<b[i]
then
begin
writeln(i);
bo:=false;
break;
end
else
begin
c:=c+a
div
100*100;
dec(a,b[i]);
a:=a
mod
100;
end;
end;
if
bo
then
writeln(a+c+c
div
5);
end.

阅读全文

与动态规划水算法题相关的资料

热点内容
堵车如何缓解压力 浏览:15
喜鹊快贷app怎么了 浏览:263
海龟编辑器积木编程怎么安装 浏览:185
程序员理发店生意怎么样 浏览:603
程序员罗技 浏览:180
软考初级程序员课程2021下载 浏览:491
杭州程序员奶奶 浏览:880
不听命令造成错误 浏览:981
kool系统源码 浏览:610
流氓app在哪里看 浏览:98
域名购买了怎么指向服务器 浏览:121
安卓手机如何让照片颜色反转 浏览:859
怎么下载卓睿安手机版 浏览:514
h3crange命令 浏览:468
php前景和python 浏览:338
php压缩图片内存大小 浏览:495
在哪里可以查看云服务器的信息 浏览:70
python读取非txt文件 浏览:799
艾莫迅用什么编程软件好 浏览:227
android文件存储读取 浏览:214