动态规划详细教程Word文档格式.docx

上传人:b****4 文档编号:16445803 上传时间:2022-11-23 格式:DOCX 页数:25 大小:268.91KB
下载 相关 举报
动态规划详细教程Word文档格式.docx_第1页
第1页 / 共25页
动态规划详细教程Word文档格式.docx_第2页
第2页 / 共25页
动态规划详细教程Word文档格式.docx_第3页
第3页 / 共25页
动态规划详细教程Word文档格式.docx_第4页
第4页 / 共25页
动态规划详细教程Word文档格式.docx_第5页
第5页 / 共25页
点击查看更多>>
下载资源
资源描述

动态规划详细教程Word文档格式.docx

《动态规划详细教程Word文档格式.docx》由会员分享,可在线阅读,更多相关《动态规划详细教程Word文档格式.docx(25页珍藏版)》请在冰豆网上搜索。

动态规划详细教程Word文档格式.docx

=0orc<

=0,thenw(a,b,c)returns:

1

ifa>

20orb>

20orc>

20,thenw(a,b,c)returns:

w(20,20,20)

bandb<

c,thenw(a,b,c)returns:

w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c)

otherwiseitreturns:

w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1)

这本身就是一个递归函数,要是按照函数本身写递归式,结果肯定是TLE,这里我开了一个三维数组,从w(0,0,0)开始递推,逐步产生到w(20,20,20)的值,复杂度O(n^3).

总结:

这道题是很地道的DP,因为它的子问题实在是太多了,所以将问题的结果保存起来,刘汝佳《算法艺术和信息学竞赛》中115页讲到自底向上的递推,这个例子就非常典型。

总体来说这个题目还是非常简单的,不过这个思想是地道的动态规划。

 

Pkuacm2081Recaman'

sSequence动态规划题目总结(三)

一道很简单的动态规划,根据一个递推公式求一个序列,我选择顺序的求解,即自底向上的递推,一个int数组result根据前面的值依此求出序列的每一个结果,另外一个boolean数组flag[i]记录i是否已经出现在序列中,求result的时候用得着,这样就避免了查找。

核心的java代码为:

for(i=1;

i<

=500000;

i++)

{

if(result[i-1]-i>

0&

&

flag[result[i-1]-i]==false)

{

result[i]=result[i-1]-i;

flag[result[i-1]-i]=true;

else

result[i]=result[i-1]+i;

flag[result[i-1]+i]=true;

Pkuacm1953WorldCupNoise动态规划题目总结(四)

给定一个小于45的整数n,求n位2进制数中不含相邻1的数的个数。

看似简单的一道题,如果当n=45时,对2的45次方检查,是无法完成的任务。

先分析一下这个问题:

N

以1结尾的个数

以0结尾的个数

总和

1

2

3

对于n=1来说,以1结尾、以0结尾个数都是1,总和是2,下面过度到2:

对于所有以1结尾的数,后面都可以加上0,变为n=2时以0结尾的,而只有结尾为0的数才能加上1(因为不能有两个连续0),这样就可以在n=2的格里分别填上1、2,总和算出来为3,以此类推,我们可以算出所有n<

=45的值,然后根据输入进行相应输出。

核心代码如下:

inti,num,count,array[50][2],j=0;

array[1][1]=1;

array[1][0]=1;

for(i=2;

50;

array[i][0]=array[i-1][1];

array[i][1]=array[i-1][1]+array[i-1][0];

我们可以继续找出规律,其实这个就是斐波那切数列数列:

F[N]=F[N-1]+F[N-2];

可以继续简化代码。

Pkuacm1458CommonSubsequence动态规划题目总结(五)

求两个string的最大公共字串,动态规划的经典问题。

算法导论有详细的讲解。

下面以题目中的例子来说明算法:

两个string分别为:

abcfbc和abfca。

创建一个二维数组result[][],维数分别是两个字符串长度加一。

我们定义result[i][j]表示Xi和Yj的最长子串(LCS).当i或j等于0时,result[i][j]=0.LCS问题存在一下递归式:

result[i][j]=0i=0orj=0

result[i][j]=result[i-1][j-1]Xi==Yj

result[i][j]=MAX(result[i-1][j],result[i][j-1])Xi!

=Yj

对于以上例子,算法如下:

Result[i][j]:

a

b

c

f

4

5

6

从最后一个格向上顺着箭头的方向可以找到最长子串的构成,在有箭头组成的线段中,含有斜向上的箭头对应的字符是其中的一个lcs。

Java代码的核心部分如下:

for(inti=0;

length1;

i++){

result[i][0]=0;

length2;

result[0][i]=0;

for(inti=1;

=length1;

for(intj=1;

=length2;

if(str1.charAt(i-1)==str2.charAt(j-1))

result[i][j]=result[i-1][j-1]+1;

else

result[i][j]=result[i-1][j]>

result[i][j-1]?

result[i-1][j]:

result[i][j-1];

System.out.println(result[length1][length2]);

Pkuacm2250Compromise动态规划题目总结(六)

这个也是求最长公共字串,只是相比CommonSubsequence需要记录最长公共字串的构成,此时箭头的标记就用上了,在程序中,用opt[][]存放标记,0表示朝向左上方,1表示指向上,-1表示指向左。

result[][]存放当前最大字串长度。

在求最优解时,顺着箭头从后向前寻找公共字串的序号,记录下来,输出即可。

该算法在算法导论中有详细的讲解。

Pkuacm1159Palindrome动态规划题目总结(七)

给一个字符串,求这个字符串最少增加几个字符能变成回文,如Ab3bd可以增加2个字符变为回文:

Adb3bdA。

通过这样的结论可以和最长公共子串联系起来(未证明):

S和S'

(注:

S'

是S的反串)的最长公共子串其实一定是回文的。

这样我们就可以借助lcs来解决该题,即用s的长度减去lcs的值即可。

核心的Java代码为:

total-LCS(string,newStringBuffer(string).reverse().toString());

//函数LCS返回两个string的lcs的长度

Pkuacm1080HummanGeneFunction动态规划题目总结(八)

这是一道比较经典的DP,两串基因序列包含A、C、G、T,每两个字母间的匹配都会产生一个相似值,求基因序列(字符串)匹配的最大值。

这题有点像求最长公共子序列。

只不过把求最大长度改成了求最大的匹配值。

用二维数组opt[i][j]记录字符串a中的前i个字符与字符串b中的前j个字符匹配所产生的最大值。

假如已知AG和GT的最大匹配值,AGT和GT的最大匹配值,AG和GTT的最大匹配值,求AGT和GTT的最大匹配值,这个值是AG和GT的最大匹配值加上T和T的匹配值,AGT和GT的最大匹配值加上T和-的匹配值,AG和GTT的最大匹配值加上-和T的匹配值中的最大值,所以状态转移方程:

opt[i][j]=max(opt[i-1][j-1]+table(b[i-1],a[j-1]),opt[i][j-1]+table('

-'

a[j-1]),opt[i-1][j]+table('

b[i-1]));

Null

A

G

T

-3

-5

-6

-8

-11

-12

-14

-2

-4

-7

-9

第0行,第0列表示null和字符串匹配情况,结果是’-’和各个字符的累加:

for(i=1;

=num1;

opt[0][i]=opt[0][i-1]+table('

a[i-1]);

for(i=1;

=num2;

opt[i][0]=opt[i-1][0]+table('

b[i-1]);

opt[num2][num1]即为所求结果。

Pkuacm2192Zipper动态规划题目总结(九)

这个题目要求判断2个字符串能否组成1个字符串,例如cat和tree能组成tcraete。

我们定义一个布尔类型的二维数组array,array[i][j]表示str1[i]和str2[j]能否组成str[i+j].i=0或者j=0表示空字符串,所以初始化时,array[0][j]表示str1的前j个字符是否和str都匹配。

对于str=tcraete:

t

r

e

可以证明:

当array[i-1][j](array[i][j]上面一格)和array[i][j-1](array[i][j]左面一格)都为0时,array[i][j]为0.当array[i-1][j](array[i][j]上面一格)为1且左面字母为str[i+j]时或者当array[i][j-1](array[i][j]左面一格)为1且上面字母为str[i+j]时,array[i][j]为1.这就是状态转移方程为。

核心的Java代码:

if(array[i][j-1]&

str1.charAt(j-1)==str.charAt(i+j-1)||array[i-1][j]&

str2.charAt(i-1)==str.charAt(i+j-1))

array[i][j]=true;

else

array[i][j]=false;

Pkuacm3356AGTC动态规划题目总结(十)

一个字符串可以插入、删除、改变到另一个字符串,求改变的最小步骤。

和最长公共子序列类似,用二维数组opt[i][j]记录字符串a中的前i个字符到字符串b中的前j个字符匹配所需要的最小步数。

假如已知AG到GT的最小步数,AGT到GT的最小步数,AG到GTT的最小步数,求AGT到GTT的最小步数,此时T==T,这个值是AG到GT的最小步数,AGT到GT的最小步数加一(AGT到GT的最小步数等于AGTT到GTT的最小步数,加一是将T删除的一步),AG到GTT的最小步数加一(AG到GTT的最小步数等于AGT到GTTT的最小步数,加一是在AGT上增加T的一步)。

假如已知AG到GT的最小步数,AGA到GT的最小步数,AG到GTT的最小步数,求AGA到GTT的最小步数,此时A!

=T,这个值是AG到GT的最小步数加一(A改变为T),AGA到GT的最小步数加一(AGA到GT的最小步数等于AGAT到GTT的最小步数,加一是将T删除的一步),AG到GTT的最小步数加一(AG到GTT的最小步数等于AGA到GTTA的最小步数,加一是在GTTA上删除A的一步)。

所以状态转移方程:

if(str1.charAt(i-1)==str2.charAt(j-1))

array[i][j]=Math.min(Math.min(array[i-1][j-1],array[i-1][j]+1),array[i][j-1]+1);

array[i][j]=Math.min(Math.min(array[i-1][j-1]+1,array[i-1][j]+1),array[i][j-1]+1);

初始化的时候和最长公共子序列不同,因为第0行,第0列表示null转化到字符串情况,结果是字符串的长度:

=m;

array[i][0]=i;

}

=n;

array[0][i]=i;

7

结果是array[m][n]

Pkuacm1887TestingtheCATCHER动态规划题目总结(十一)

题目叙述很繁琐,其实就是求最长下降子序列,这一类题也是动态规划的典型题。

这类问题有两种算法,一种T(o)=O(n^2),另一种T(o)=O(nlogn),这里用第一种,在1631Bridgingsignals的解题报告中介绍第二种。

创建一个一维数组num_array[j],max_array[],num_array[j]表示序列的元素,max_array[i]表示以第i个元素结尾的序列中的最长下降子序列,初始化为1,对于一个max_array[i],遍历前面的每个元素j,如果num_array[j]>

num_array[i]且max_array[j]>

=max_array[i],那么max_array[j]就要加1,所以递推公式为:

if(num_array[i]<

=num_array[j]&

max_array[i]<

=max_array[j])

max_array[i]++;

最后选最大的一个max_array[i]就是最长下降子序列的个数。

Java关键部分的代码:

length;

i;

if(num_array[i]<

max_array[i]++;

max_value=(max_array[i]>

max_value)?

max_array[i]:

max_value;

max_value是最后的结果。

Pkuacm2533LongestOrderedSubsequence动态规划题目总结(十二)

这个题目和1887TestingtheCATCHER一模一样,没有什么值得说的,关键的c代码如下:

for(j=1;

j++)

if(max[i]<

=max[j]&

num[i]>

num[j])

max[i]++;

if(max[i]>

result)

result=max[i];

printf("

%d\n"

result);

Pkuacm1631Bridgingsignals动态规划题目总结(十三)

这个题目可以转化为最长上升子序列,这样这个题目似乎就和2533LongestOrderedSubsequence1887TestingtheCATCHER一样了,迅速写下代码,结果超时!

看来只能用O(nlogn)的算法了。

在O(n^2)的算法中:

创建一个一维数组array[j],opt[],array[j]表示序列的元素,opt[i]表示以第i个元素结尾的序列中的最长下降子序列,初始化为1,对于一个opt[i],遍历前面的每个元素j,如果array[j]>

array[i]且opt[j]>

=opt[i],那么opt[j]就要加1,在这里,遍历前面的每个元素j,寻找此前最大的子序列时间复杂度为O(n),如果我们在一个有序的序列中查找此前最大的序列长度,我们就可以用二分查找,时间复杂度就会降为O(logn),总的时间复杂度就会为O(nlogn)。

为此,我们增加一个一维数组B,B[i]表示当前序列为i的末尾元素的最小值。

例如对于序列:

426315:

i

array

opt

B

构建过程如下:

i=1时,opt[i]=1B[i]=4(当前为1的序列的末尾元素的最小值)

i=2时,2不大于4,所以opt[i]=1,将B[1]更新为2

i=3时,6大于2,所以opt[i]=1+1,将B[2]更新为6

i=4时,3在26之间,所以opt[i]=1+1,将B[2]更新为3

i=5时,1小于2,所以opt[i]=1,将B[1]更新为1

i=6时,5大于3,所以opt[i]=2+1,将B[3]更新为5

opt[6]就是最后的结果。

从构建的过程可以容易的证明一下两点:

B是递增的。

B是当前序列为i的末尾元素的最小值。

以上“2不大于4”,“3在26之间”等等的判断采用二分查找,所以总的时间复杂度为:

O(nlogn),核心的c代码如下:

num=array[i];

left=1;

right=Blen;

while(left<

=right)

mid=(left+right)/2;

if(B[mid]<

num)

left=mid+1;

right=mid-1;

opt[i]=

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 合同协议

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1