ACM DP训练专辑

Pku acm 1163 the Triangle  动态规划题目总结(一)

题目:http://acm.pku.edu.cn/JudgeOnline/problem?id=1163

对于一个有数字组成的二叉树,求由叶子到根的一条路径,使数字和最大,如:

7

3     8

8   1   0

2   7   4   4

4   5   2   6   5

这个是经典的动态规划,也是最最基础、最最简单的动态规划,典型的多段图。思路就是建立一个数组,由下向上动态规划,保存页子节点到当前节点的最大值,Java核心代码如下:

for(int i=num-2;i>=0;i--){

for(int j=0;j<=i;j++){

//该句是整个动态规划的核心

number[i][j]=Math.max(number[i+1][j],number[i+1][j+1])+number[i][j];

}

}

带有详细注释的代码可以在http://download.csdn.net/user/china8848/获得

 

Pku acm 1579 Function Run Fun  动态规划题目总结(二)

http://acm.pku.edu.cn/JudgeOnline/problem?id=1579

Consider a three-parameter recursive function w(a, b, c):
if a <= 0 or b <= 0 or c <= 0, then w(a, b, c) returns: 1
if a > 20 or b > 20 or c > 20, then w(a, b, c) returns: w(20, 20, 20)
if a < b and b < c, then w(a, b, c) returns: w(a, b, c-1) + w(a, b-1, c-1) - w(a, b-1, c)
otherwise it returns: 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页讲到自底向上的递推,这个例子就非常典型。总体来说这个题目还是非常简单的,不过这个思想是地道的动态规划。

带有详细注释的代码可以在http://download.csdn.net/user/china8848/获得

 

 

 

Pku acm 2081 Recaman's Sequence 动态规划题目总结(三)

http://acm.pku.edu.cn/JudgeOnline/problem?id=2081

一道很简单的动态规划,根据一个递推公式求一个序列,我选择顺序的求解,即自底向上的递推,一个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;

}

}

带有详细注释的代码可以在http://download.csdn.net/user/china8848/获得

 

Pku acm 1953 World Cup Noise  动态规划题目总结(四)

http://acm.pku.edu.cn/JudgeOnline/problem?id=1953

给定一个小于45的整数n,求n位2进制数中不含相邻1的数的个数。看似简单的一道题,如果当n=45时,对2的45次方检查,是无法完成的任务。先分析一下这个问题:

N

以1结尾的个数

以0结尾的个数

总和

1

1

1

2

2

1

2

3

3

对于n=1来说,以1结尾、以0结尾个数都是1,总和是2,下面过度到2:对于所有以1结尾的数,后面都可以加上0,变为n=2时以0结尾的,而只有结尾为0的数才能加上1(因为不能有两个连续0),这样就可以在n=2的格里分别填上1、2,总和算出来为3,以此类推,我们可以算出所有n<=45的值,然后根据输入进行相应输出。核心代码如下:

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

array[1][1] = 1;

array[1][0] = 1;

for(i=2;i<50;i++)

{

        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];可以继续简化代码。

带有详细注释的代码可以在http://download.csdn.net/user/china8848/获得

Pku acm 1458 Common Subsequence  动态规划题目总结(五)

http://acm.pku.edu.cn/JudgeOnline/problem?id=1958

求两个string的最大公共字串,动态规划的经典问题。算法导论有详细的讲解。

下面以题目中的例子来说明算法:两个string分别为:abcfbc和abfca。创建一个二维数组result[][],维数分别是两个字符串长度加一。我们定义result[i][j]表示Xi和Yj 的最长子串(LCS).当i或j等于0时,result[i][j]=0. LCS问题存在一下递归式:

result[i][j] = 0                            i=0 or j=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

b

a

 

 

0

1

2

3

4

5

6

 

0

0

0

0

0

0

0

0

a

1

0

1

1

1

1

1

1

b

2

0

1

2

2

2

2

2

f

3

0

1

2

2

3

3

3

c

4

0

1

2

3

3

3

3

a

5

0

1

2

3

3

3

4

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

Java代码的核心部分如下:

for(int i=0;i<length1;i++){

     result[i][0] = 0;

}

for(int i=0;i<length2;i++){

     result[0][i] = 0;

}

for(int i=1;i<=length1;i++){

     for(int j=1;j<=length2;j++){

        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]);

 

带有详细注释的代码可以在http://download.csdn.net/user/china8848/获得

 

 

 

 

Pku acm 2250 Compromise 动态规划题目总结(六)

http://acm.pku.edu.cn/JudgeOnline/problem?id=2250

这个也是求最长公共字串,只是相比Common Subsequence需要记录最长公共字串的构成,此时箭头的标记就用上了,在程序中,用opt[][]存放标记,0表示朝向左上方,1表示指向上,-1表示指向左。result[][]存放当前最大字串长度。在求最优解时,顺着箭头从后向前寻找公共字串的序号,记录下来,输出即可。该算法在算法导论中有详细的讲解。

带有详细注释的代码可以在http://download.csdn.net/user/china8848/获得。

 

Pku acm 1159 Palindrome 动态规划题目总结()

http://acm.pku.edu.cn/JudgeOnline/problem?id=1159

给一个字符串,求这个字符串最少增加几个字符能变成回文,如Ab3bd可以增加2个字符变为回文:Adb3bdA。通过这样的结论可以和最长公共子串联系起来(未证明):S和S' (注:S'是S的反串)的最长公共子串其实一定是回文的。这样我们就可以借助lcs来解决该题,即用s的长度减去lcs的值即可。核心的Java代码为:

total-LCS(string,new StringBuffer(string).reverse().toString());

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

带有详细注释的代码可以在http://download.csdn.net/user/china8848/获得

 

Pku acm 1080 Humman Gene Function  动态规划题目总结(八)

http://acm.pku.edu.cn/JudgeOnline/problem?id=1080

这是一道比较经典的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

G

A

T

G

Null

 

-3

-5

-6

-8

-11

-12

-14

G

-2

 

 

 

 

 

 

 

T

-3

 

 

 

 

 

 

 

T

-4

 

 

 

 

 

 

 

A

-7

 

 

 

 

 

 

 

G

-9

 

 

 

 

 

 

 

第0行,第0列表示null和字符串匹配情况,结果是’-’和各个字符的累加:      for(i=1;i<=num1;i++)

            opt[0][i] = opt[0][i-1]+table('-',a[i-1]);

    for(i=1;i<=num2;i++)

            opt[i][0] = opt[i-1][0]+table('-',b[i-1]);

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

带有详细注释的代码可以在http://download.csdn.net/user/china8848/获得

Pku acm 2192 Zipper  动态规划题目总结(九)

http://acm.pku.edu.cn/JudgeOnline/problem?id=2192

这个题目要求判断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:

 

Null

c

a

t

Null

1

0

0

0

t

1

 

 

 

r

0

 

 

 

e

0

 

 

 

e

0

 

 

 

可以证明:当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;

带有详细注释的代码可以在http://download.csdn.net/user/china8848/获得

 

 

Pku acm 3356 AGTC  动态规划题目总结(十)

http://acm.pku.edu.cn/JudgeOnline/problem?id=3356

一个字符串可以插入、删除、改变到另一个字符串,求改变的最小步骤。和最长公共子序列类似,用二维数组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);

else

    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转化到字符串情况,结果是字符串的长度:

for(int i=0;i<=m;i++){

    array[i][0] = i;

}  

for(int i=0;i<=n;i++){

    array[0][i] = i;

}

 

Null

A

G

T

G

A

T

G

Null

0

1

2

3

4

5

6

7

G

1

 

 

 

 

 

 

 

T

2

 

 

 

 

 

 

 

T

3

 

 

 

 

 

 

 

A

4

 

 

 

 

 

 

 

G

5

 

 

 

 

 

 

 

结果是array[m][n]

带有详细注释的代码可以在http://download.csdn.net/user/china8848/获得

 

 

Pku acm 1887 Testing the CATCHER  动态规划题目总结(十一)

http://acm.pku.edu.cn/JudgeOnline/problem?id=1887

题目叙述很繁琐,其实就是求最长下降子序列,这一类题也是动态规划的典型题。这类问题有两种算法,一种 T(o) = O(n^2),另一种T(o) = O(nlogn),这里用第一种,在1631 Bridging signals的解题报告中介绍第二种。

创建一个一维数组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关键部分的代码:

for(int i=1;i<length;i++){

         for(int j=0;j<i;j++){

            if(num_array[i]<=num_array[j]&&max_array[i]<=max_array[j])

                max_array[i]++;

         }

         max_value = (max_array[i]>max_value)?max_array[i]:max_value;

}

max_value是最后的结果。

带有详细注释的代码可以在http://download.csdn.net/user/china8848/获得

 

 

 

Pku acm 2533 Longest Ordered Subsequence  动态规划题目总结(十二)

http://acm.pku.edu.cn/JudgeOnline/problem?id=2533

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值