动态规划(七)

17
动动动动 动动 ()

Upload: lawrence-oneill

Post on 30-Dec-2015

53 views

Category:

Documents


0 download

DESCRIPTION

动态规划(七). 乘法问题. 问题描述:设有1个长度为 n 的数字字符串,分成 k+1 个部分,使得 k+1 个部分的乘积为最大。 [样例]输入: 6 3 n=6, k=3 310143 输出:3720. 分析. 最优子结构分析 设数字字符串为 a1a2…a n K=1 时,一个乘号可以插在 a1a2…a n 中的 n-1 个位置,这样就得到 n-1 个子串的乘积: a1*a2…a n , a1a2*a3…a n , …, a1a2…a n-1 *a n - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 动态规划(七)

动态规划(七)

Page 2: 动态规划(七)

乘法问题问题描述:设有 1 个长度为 n 的数字字符串,分成 k+1 个部分,使得k+1 个部分的乘积为最大。[ 样例 ] 输入:

6 3 n=6, k=3

310143

输出: 3720

Page 3: 动态规划(七)

分析最优子结构分析设数字字符串为 a1a2…an

K=1 时,一个乘号可以插在 a1a2…an 中的 n-1 个位置,这样就得到 n-1 个子串的乘积:a1*a2…an, a1a2*a3…an, …, a1a2…a n-1*an

此时的最大值 = max{a1*a2…an, a1a2*a3…an, …, a1a2…a n-1*an }

K=2 时,二个乘号可以插在 a1a2…an 中 n-1 个位置的任两个地方,这样总共会产生 12

)2()1(21

nnCn

个乘积。把这些乘积分个类,便于观察规律。

Case1: a1a2 …*a n-1*an , a1a2 …*a n-2 a n-1*an , a1*a2 …a n-3 a n-2 a n-1*an ,

因后一个乘号位置不变,要使这些乘积最大,就要找出在前 n-1 个数中插入一个乘号的最大值。设符号 F[n-1,1] 为在前 n-1 个数中插入一个乘号的最大值 , 则

Case1 的最大值为 F[n-1,1]*an

Page 4: 动态规划(七)

分析Case2: a1a2 …*a n-2*a n-1 an , a1a2 …*a n-3 a n-2* a n-1 an , a1*a2 …a n-3 a n-2* a

n-1 an ,

因后一个乘号位置不变,要使这些乘积最大,就要找出在前 n-2 个数中插入一个乘号的最大值。设符号 F[n-2,1] 为在前 n-2 个数中插入一个乘号的最大值 , 则

Case2 的最大值为 F[n-2,1]*a n-1 an

同理, Case3 的最大值为 F[n-3,1]* a n-2 a n-1 an

……

Case n-2 的最大值为 F[2,1]*a3…an

Page 5: 动态规划(七)

分析下面以 n=9, k=4, s=‘321044105’ 为例,说明计算过程。

n 1 2 3 4 5 6 7 8 9

K=0 3 32 321 3210 32104 321044 3210441 32104410 321044105

1 - 6 63 630 12840 128416 - - -

2 - - 6 60 2520 51360 526440 - -

3 - - - 0 240 10080 103320 1033200 -

4 - - - - 0 960 10080 100800 5166000

其实在上面显示的计算过程中,我们未显示出右子串是什么,但它实际上是要参加运算的。我们引入符号 f[i,s] 表示从 a1~aj 中插入 s 个乘号取得的最大值, g[I,j] 表示从 ai~aj 的子串的数值。则上式可表示为:

f[9,4] = max{f[8,3]*g[9,9], f[7,3]*g[8,9], f[6,3]*g[7,9], f[5,3]*g[6,9], f[4,3]*g[5,9]}

F[8,3] = max{f[7,2]*g[8,8], f(6,2]*g[7,8], f[5,2]*g[6,8], f[4,2]*g[5,8],f[3,2]*g[4,8]}

F[7,3] = max{f[6,2]*g[7,7], f[5,2]*g[6,7], f[4,2]*g[5,7], f[3,2]*g[4,7]}

……

F[7,2] = max{f[6,1]*g[7,7], f[5,1]*g[6,7], f[4,1]*g[5,7], f[3,1]*g[4,7], f[2,1]*g[3,7]}

……

F[6,1] = max {f[5,0]*g[6,6], f[4,0]*g[5,6], f[3,0]*g[4,6], f[2,0]*g[3,6], f[1,0]*g[2,6]}

……

Page 6: 动态规划(七)

分析上面的分析已经看出问题的最优子结构性质。下面是递归地定义问题的最优解。F[I,j] = max{f[I-1,j-1]*g[I,I], f[I-2,j-1]*g[I-1,I], f[I-3,j-1]*g[I-2,I], …., f[j,j-1]*g[j+1,I]} (1<=I<=n, 1<=j<=k)

上式的边界条件是什么? f[I,0] =g[1,I] (1<=I<=n)

我们要求的问题的最优解是 f[n,k].

Page 7: 动态规划(七)

分析阶段:我们看到在 f[n,k] 中有二个自变量,到底选择哪个作为阶段变量呢?由于子问题是在子串中插入 k-1,k-2, …,1,0 个乘号,因此,把 k 作为阶段变量。阶段数 J 为 1~k ,表示在子串中插入 J 个乘号。初始阶段为 k=0 ,表示在子串中插入 0 个乘号。这也就是上面分析过的边界条件: f[I,0] =g[1,I] (1<=I<=n)

想一想,怎样用程序段实现这个初始阶段? for I:= 1 to n do

f[I,0] := g[1, I];

Page 8: 动态规划(七)

分析状态数分析状态数分析是本题的难点。但对题意作深入理解后,就会逐渐理解状态数该如何确定。请记住,状态变量是阶段变量的函数,它会随着阶段变量的改变而变化。阶段数 J ,表示在子串中插入 J 个乘号。那么最少是多长的子串才能刚好插入这 J 个乘号呢?应该是长度为 J+1 的子串。这就是 J 阶段的起始状态:在长度为 J+1 的子串中插入 I 个乘号。再思考状态数的上界。最长允许的子串是多少呢?请记住还有 k-J 个乘号需要插入右子串中。与上面类似,右子串最短刚好容纳 K-J 个乘号的长度为 K-J+1 ,而整个字串的长度为 n ,故左子串最长允许的长度为 n-(k-J+1) = n+J-k-1

总结起来,状态数 I 的取值范围就是 J+1 <= I <= n+J-k-1

Page 9: 动态规划(七)

分析决策数分析阶段、状态确定了,要求解的当前问题也就确定了:在长度为 I 的子串中插入 J 个乘号的最优解是多少?用符号表示就是求 F[I,J] 的值。前面已经分析过,这一问题可以理解为用第 J 个乘号把长度为 I 的字串分左、右二个子串,左子串中插有 J-1 个乘号,求得它的最优解,再乘以右子串的问题。与状态数分析相似的问题又来了:这第 J 个乘号可以放在长度为 I 的字串的哪些位置呢?由于左子串要插入 J-1 个乘号,因此左子串的最短长度为 J-1+1 = J ,这就是决策变量的起始值,也就是下界。由于第 J 个乘号一定要分出左右子串来,右子串最短为 1 ,此时左子串最长为 I-1 ,这就是决策变量的终值,也就是上界。总结起来,决策变量的取值范围是: J<= p <= I-1

Page 10: 动态规划(七)

分析做什么决策?求 f[I,J] 的决策。前边分析过:

F[I,j] = max{f[I-1,j-1]*g[I,I], f[I-2,j-1]*g[I-1,I], f[I-3,j-1]*g[I-2,I], …., f[j,j-1]*g[j+1,I]}

我们看到左子串的长度在变化,用决策变量 P 代替,上式变为:f[I,j] = max{f[p,j-1]*g[p+1,I]} (J<= p <= I-1)

这个熟悉的数学式大家知道该怎样转化成 for 循环结构了吧。

Page 11: 动态规划(七)

分析G[I,j] 的处理G[I,J] 的定义是从字串的 ai~aj 的数值。没有现成的方法可以把一个字符串转换成一个长整型数据。因此需要我们自行定义函数。数字字符转化为对应整数的方法是利用求序号函数ORD ,它可以求出字符的 ASCII 码:

ORD(‘5’) - ORD(‘0’) = 5 ORD(‘9’) - ORD(‘0’) = 9 将一个数字字串转化为对应的整数的代码段是: d := 0; for I:= 1 to Length(str) do d := d * 10 + ord(str[I]) – ord(‘0’); {str 是字符串类型,也可以看成字符数组 }下面是定义函数 g(I,j) 的代码:Function g(str:string; I,j:integer):longint; { 从 str 中取出 ai~aj 的数字 }Var d : longint; k : integer;Begin d := 0; for k := I to j do d := d * 10 + ord(str[k]) – ord(‘0’); g := d;End;

Page 12: 动态规划(七)

分析注意程序中用到的变量的数据类型的选择。数组 f[1..n, 0..k] 应是什么类型?注意凡是程序中出现的用于保存 f[I,j] 值的工作变量都应与它的类型一致。

Page 13: 动态规划(七)

练习请自行完成程序。请思考本题输入的数字字符串的长度限制是多少?如果要处理比长整型长得多的数字字符串,程序要作哪些修改?

Page 14: 动态规划(七)

进一步编程题加法问题。问题描述:设有 1 个长度为 n 的数字字符串,数字由 1~9 组成。分成k+1 个部分,使得 k+1 个部分的和为最小。数值范围( 5<=N<=40 , 1<=K<=20 , k<n)

[ 样例 ] 输入: 79846 2

输出:133

输入: 82363983742 3

输出: 2170

Page 15: 动态规划(七)

进一步编程题乘积最大 (NOIP 2000 第二题 ) 问题描述 :今年是国际数学联盟确定的“ 2000——世界数学年”,又恰逢我国著名数

学家华罗庚先生诞辰 90周年。在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友 XZ 也有幸得以参加。活动中,主持人给所有参加活动的选手出了这样一道题目 :

设有一个长度 N的数字串,要求选手使用 K个乘号将它分成 K+1 个部分,找出一种分法,使得这 K+1 个部分的乘积能够为最大。

同时,为了帮助选手能够正确理解题意,主持人还举了如下的一个例子:有一个数字串 : 312,当 N=3 , K=1 时会有以下两种分法:

1) 3*12=362) 31*2=62

这时,符合题目要求的结果是: 31*2=62现在,请你帮助你的好朋友 XZ 设计一个程序,求得正确的答案。

Page 16: 动态规划(七)

进一步编程题输入:

程序的输入共有两行 :第一行共有 2个自然数 N,K (6<=N<=40 , 1<=K<=6)第二行是一个 K度为 N的数字串。

输出 :结果显示在屏幕上,相对于输入,应输出所求得的最大乘积(一个自然数)。

样例 :输入4 21231

输出62

Page 17: 动态规划(七)

进一步编程题求函数最大值已知 3个函数 A , B , C 值如下表示,自变量取值为 0~10的整数。请用动态规划的方法求出一组 x , y , z,使得 A(x)+B(y)+C(z)为最大,并且满足 x2+y2+z2<N , N由键盘输入。

X 0 1 2 3 4 5 6 7 8 9 10A(x) 2 4 7 11 13 15 18 22 18 15 11B(x) 5 10 15 20 24 18 12 9 5 3 1C(x) 8 12 17 22 19 16 14 11 9 7 4