我们可以用一个三元组(X,Y,Z)描述半连续多边形,D(X,Y,Z)表示半连续多边形(X,Y,Y+1,…,Z)的划分区域数。 根据性质2-1,对半连续多边形(X, Y, Z)可以只考虑顶点X 的划分,划分后的多边形仍然是半连续多边形,于是,状态表示2-2不但可以描述问题的特征,也可以正确描述子问题的特征。考虑到(X,Y,Z)最优划分包含了它的子半连续多边形的最优划分,状态表示2-2描述的子问题满足最优子结构性质。 根据定义,初始多边形是一个半连续多边形,表示为(1,2,N)。状态转移方程为 D(X,Y,Z) = Min {D(Y,Y+1,Z)+g(X,Y,Z), D(X,J,Z)+D(X,Y,J)}, Z<J<Y f(J,I,I) = 0, n+1>I>J>0, 当X,Y,Z在一条直线时,g(X,Y,Z) = 0, 否则g(X,Y,Z) = 1。 状态表示2-2的子问题空间只有 O(n3),动态规划最多可以处理顶点数 80的多边形。以下给出求半连续多边形最优划分区域数的函数。 [算法2-2]: function Dynamic(x, y, z : integer) : integer; {求半连续多边形(x,y, z)的最优划分} var j, tot : integer; begin if D[x, y, z] = 255 then if y - z = 1 then if x,y,z三点共线 then D[x, y, z] := 0 else D[x,y,z] := 1 else begin if 顶点y与顶点z连接合法 then begin D[x,y,z] := Dynamic(y,y+1,z); If x,y,z 三点不共线 then D[x,y,z] := D[x,y,z]+1; End; for j := y + 1 to z - 1 do {j 是顶点x要连接的顶点} if 顶点x与顶点j 连接合法then begin Tot := Dynamic(x, y, j) + Dynamic(x, j, z); {子多边形的最优划分} if Tot < D[x, y, z] then begin D[x, y, z] := Tot; end; end; end; Dynamic := D[x, y, z]; end;
连续多边形(X,X+1,,…,Y)可以用二元组(X,Y)来表示,则D(X,Y)表示连续多边形的划分区域数。 对于连续多边形(X,Y),只要我们选择边(X,Y)与顶点Z(X<Z<Y)连接,那么(X,Y)划分为三部分:连续多边形(X,Z)、连续多边形(Z,Y)和三角形(X,Z,Y)。(X,Y)的最优划分包含了(X,Z)、(Z,Y)的最优划分,满足最优子结构性质。 注意到初始多边形是一个连续多边形,根据数学归纳法,它的子问题都是连续多边形。因此二元组(X,Y)是一个正确的状态表示。状态转移方程为 D(X,Y) = min(g(X,Y,Z) + D(X,Z)+D(Z,Y)), X<Z<Y, f(i,i) = 0, n+1>i>0, 当x,y,z在一条直线时,g(x,y,z) = 0, 否则g(x,y,z) = 1。 子问题空间复杂度是O(n2),在本文的假设条件下,使用基本堆空间可以处理顶点数700以内的多边形。下面是求连续多边形最优划分区域数的函数。 [算法2-3]: function Dynamic(s, t : integer) : integer; {求连续多边形(s,t)的最优划分} var j, tot : integer; begin if D[s, t][1] = 255 then if t - s = 1 then D[s, t][1] := 0 else begin for j := s + 1 to t - 1 do {j 是边(s,t)要连接的顶点} if 顶点j与顶点s、t连接合法 then begin Tot := Dynamic(s, j) + Dynamic(j, t); {子多边形的最优划分} If 顶点s、t、j不在一条直线上 then Tot := Tot + 1; if Tot < D[s, t][1] then begin D[s, t][1] := Tot; D[s, t][2] := j; end; end; end; Dynamic := D[s, t][1]; end;
运算时,我们描述的是正整数k的各位数字和、最大数字和最小数字两个信息(这里把最大、最小数字看成一个信息)以及得到k所用的最少 # 数,那么可以有两种状态表示。 状态表示3-1 我们用一元组(k)表示正数k, D(k)表示所用的#数目。(k)已经隐含了各数字和、最大数字和最小数字两个信息。 状态表示3-2 因为对每个数而言,各位数字和与最大数字、最小数字两个信息具有独立性,我们可以分别记录这两个信息。用一元组(X)表示各位数字和,用二元组(Y,Z)表示最大数字、最小数字。 我们对输入的数a进行特殊处理,而一次运算后的最大数字不超过738,状态表示3-1只要开一个数组,定义如下 Type NumBerType = array[1..738] of integer 因为一次运算后的数值最大是三位数,各位数值和不超过27,用来存储数值和的数组可定义为 Type TotalType = array[1..27] of integer 最大数字、最小数字与数大小无关,它们范围在[0,9],定义为 Type MaxMinType = array[0..9,0..9] of integer 状态表示3-1用一元组同时记录了两个信息,而状态表示3-2则分别记录了这两个信息。显然状态表示3-2所用的空间比状态表示3-1所用的要小的多。同样一个对象,只是由于我们采取不同的描述方法,所用的空间大小就迥然不同。程序见附录。