1 n←length(T)2 create array x[1:L]3 for j←1 to L4 d o x[j]←j/T[1]5 for i←2 to n6 do for j←L to 17 do for k←1 to j/T[i]8 do if x[j-k*x]+k<x[j]9 then x[j]←x[j-k*x]+k10 return x时间复杂度分析:算法1~2行时间复杂度为O(1),3~4行时间复杂度为O(L),5~9行时间复杂度为O(nL2),10行时间复杂度为O(1)。
故算法总的时间复杂度为O(nL2)。
(3)设y[1:n]存储当找钱数为j的最优解时T[1:n]硬币分别找的个数。
选择面值最大的T[i],1≤i≤n,使C[n,j]=C[n,j-T[i]]+1,则子问题找钱数为j-T[i]的最优解y’[1:n]中,y’[i]+1后即为原问题的最优解y[1:n]。
故问题的最优解可以通过子问题的最优解来达到,该问题具有贪心选择性。
(假设T[1:n]的面值是递增的,并且C[n,L]是与排序后的T对应的结果)Input:T[1:n], C[1:L], mOutput:每个硬币对应的数目y[1:n]GET-CHANGE-NUMBER(T,C,m)1 n←length(T),w←m2 create array y[1:n]3 for i←1 to n4 do y[i]←05 while w>06 do for i←n to 17 do if C[w]=C[w-T[i]]+18 then y[i]←y[i]+19 w←w-T[i]10 break11 return y时间复杂性分析:算法1~2行时间复杂度为O(1),2~3行时间复杂度为O(n),5~10行时间复杂度为O(m×n),11行时间复杂度为O(1)。
故算法总的时间复杂度为O(m×n)。
2.设计一个动态规划算法从n个数构成的数列中找出最长单调递增子序列。
答:(1)问题转化:设X[1:n]为n个数构成的序列,Y[1:n]为将X[1:n]中的数进行递增排序的结果。
那么,原问题可以转化为求X和Y的最长公共子序列。
设X中的最长单调递增子序列为x i, x j, …, x k, x m,那么在排序后的Y中,该子序列仍以这一顺序存在于Y中,显然该序列为X和Y的公共子序列。
假设其不是X和Y的最长公共子序列,设其最长公共子序列为x i, x j, …, x p, …, x k, x m。
由于Y为递增序列,因此有x i<x j<…<x p<…<x k<x m。
又因为x i, x j, …, x p, …, x k, x m是X的子序列,那么在X序列中,有一个更长的单调递增子序列x i, x j, …, x p, …, x k, x m。
产生了矛盾,因此X的最长单调递增子序列即为X和Y的最长公共子序列。
(2)优化子结构X和Y的LCS=(z1,z2,…,z k)的优化解结构为LCS XY=LCS X+<x m=y n> if x m=y nm−1Y n−1if x m≠y n,z k≠x mLCS XY=LCS Xm−1Yif x m≠y n,z k≠y mLCS XY=LCS XYn−1(3)递推方程C[i,j]=X i和Y j的LCS的长度C[i,j]=0 if i=0或j=0C[i,j]=C[i−1,j−1]+1 if i,j>0且x i=y jC[i,j]=max (C[i,j−1],C[i−1,j]) if i,j>0且x i=y j (4)算法伪代码Input:数列X[1:n]Output:X的最长单调递增子序列LIS(X)1 n←length(X)2 create array Y[1:n] ,C[n,n] and B[n,n]3 Y←sort(X)4 for i←1 to n5 do C[i,0]←0,C[0,j]←06 for i←1 to n7 do for j←1 to n8 if X[i]=Y[j]9 then C[i,j]←C[i-1,j-1]+1;B[i,j]←“↖”10 else if C[i-1,j]≥C[i,j-1]11 then C[i,j]←C[i-1,j]; B[i,j]←“↑”12 else C[i,j]←C[i,j-1]; B[i,j]←“←”13 return B and CPRINT-LIS(B,X,i,j)1 if i←0 or j←02 then return3 if B[i,j]= “↖”4 then PRINT-LIS(B,X,i-1,j-1);print X[i]5 else if B[i,j]= “↑”6 then PRINT-LIS(B,X,i-1,j);7 else PRINT-LIS(B,X,i,j-1);时间复杂度分析:计算代价算法LIS(X)中,1~2行时间复杂度为O(1),3行为排序算法,时间复杂度最低为O(nlogn),4~5行时间复杂度为O(n),6~12行时间复杂度为O(n2),13行时间复杂度为O(1);构造算法PRINT-LIS(B,X,i,j)中,时间复杂度为O(2n)。
故算法总的时间复杂度为O(n 2)。
3.给定一个n×n 的矩阵A ,矩阵中的元素只取0或者1。
设计一个动态规划算法,求解得到A 中元素全是1的子方阵使其阶数达到最大值。
答:(1)优化子结构:设n 阶矩阵表示为A[1:n,1:n],B[i,j]为A 中前i 行,前j 列中1的个数。
则⎩⎨⎧==++=1A[i][j] if 10A[i][j] if 0B -B B B 1-j 1,-i 1-j i,j 1,-i j i, 如果B i,j -B i-k,j - B i,j-k +B i-k,j-k =k 2,那么在该位置存在一个k 阶矩阵。
(2)递推方程:设C[i,j]表示A 中前i 行前j 列中元素全为1的子方阵的最大阶数。
则递推方程为:C [i,j ]=max {C [i −1,j ],C [i,j −1],max k{k ≥max (C [i −1,j ],C [i,j −1])| B [i,j ]−B [i −k,j ]−B [i,j −k ]+B [i −k ][j −k ]=k ×k}}(3)算法伪代码只要知道了C n,n 的值,就知道了最优解的阶数,为了知道这个最优解的具体信息,我们还需一个结构S ,S i,j 是C i,j 对应的方阵的右下角元素在A 中对应的位置。
因此,S n,n 就是最优解方阵右下角元素的位置,C n,n 是最优解的阶数。
GET-MAX-MATRIX(A,n)1 create arrays B[0:n][0:n],C[0:n][0:n],S[1:n][1:n]2 for i←0 to n3 do B[i][0]←0; B[0][i]←0;C[i][0]← 0; C[0][i]←0;4 for i←0 to n5 do for j←0 to n6 do if A[i][j]=17 then B[i][j]←18 else B[i][j]←09 B[i][j]←B[i][j]+B[i-1][j]+B[i][j-1]+B[i-1][j-1]10if C[i-1][j]>C[i][j-1]11 then C[i][j]←C[i-1][j]12 S[i][j]←C[i-1][j]13 else C[i][j]←C[i][j-1]14 S[i][j]←C[i][j-1]15 for k←C[i][j]+1 to i16 do if i-k+1<1 or j-k+1<017 then break18 if B[i][j]-B[i-k+1][j]-B[i][j-k]+B[i-k][j-k]=k×k19 then C[i][j]←k20 S[i][j] (i,j)21 else break22 return S and C算法结束后,S[n][n]中有序实数对(i,j)为A 中最大全1矩阵右下角元素的坐标。
该矩阵为A[i-C[n][n]:i][j-C[n][n]:j]。
时间复杂度分析:算法第1行时间复杂度为O(1),2~3行时间复杂度为O(n),4~22行时间复杂度为O(n 3),23行时间复杂度为O(1)。
故算法总的时间复杂度为O(n 3)。
4.集合划分问题描述如下:输入:正整数集合 S={a 1,a 2,a 3,…, a n };输出:是否存在A ⊆ S 使得∑a i =∑a i a i ∈S−A a i ∈A 。
试设计一个动态规划算法,求解集合划分问题。
答:(1)问题转化:若集合划分A 使得∑a i =∑a i a i ∈S−A a i ∈A ,则有∑a i =∑a i =12∑a i a i ∈S a i ∈S−A a i ∈A 。
那么,该问题可转化为一个0-1背包问题。
对于输入的正整数集合S={a 1,a 2,a 3,…, a n }。
设X=(x 1, x 2, …, x n ),x i ∈{0, 1}, 满足∑x i a i n i=1≤12∑a i a i ∈S ,且∑x i a i n i=1最大。
若此时∑x i a i n i=1=12∑a i a i ∈S , 则存在这样的集合划分A ,输出划分结果;否则不存在这样的集合A 。
(2)优化子结构:如果(y 1, y 2,…, y n )是0-1背包问题的有化解,则(y 2, y 3,…, y n )是如下子问题的优化解:∑x i a i n i=2≤12∑a i a i ∈S −a 1y 1;x i ∈{0, 1},2≤i ≤n 。
(3)递推方程:设背包容量为j ,m(i,j)表示背包容量为j ,可选物品为a i ,a i+1,…, a n 时,问题的最优解的代价。
因此递归方程为:m(i,j)=m(i+1,j) 0≤j<a im(i,j)=max(m(i+1,j),m(i+1,j−a i)+a i) j≥a im(n,j)=0 0≤j<a nm(n,j)=a n j≥a n(4)算法伪代码:Input:正整数集合S={a1,a2,a3,…, a n}Output:若存在A ⊆S使得∑a i=∑a ia i∈A, 则输出X; 否则输a i∈S−A出不存在。
SET-PARTITION(S)1 n←length(S),sum←02 for i←1 to n3 do sum←sum+S[i]4 half-sum←sum/25 create array m[1:n,0: half-sum] and X[1:n]6 for j←0 to min(S[n]-1, half-sum)7 do m[n,j]←08 for j←S[n] to half-sum9 do m[n,j]←S[n]10 for i←n-1 to 211 do for j←0 to min(S[i]-1, half-sum)12 do m[i,j]←m[i+1,j]13 for j←S[i] to half-sum14 do m[i,j]←max{m[i+1,j],m[i+1,j-S[i]]+S[i]}15 if half-sum <S[1]16 then m[1, half-sum]=m[2, half-sum]17 else m[1, half-sum]=max{m[2, half-sum],m[2, half-sum -S[1]]+S[1]}18 if m[1, sum/2] < sum/219 then return “不存在”20 w←half-sum21for i←1 to n-122 do if m[i,w]=m[i+1, w]23 then X[1]=024 else X[1]=125 w←w-S[i]26 if w≥S[n]27 then X[n]=028 else X[n]=129 return X时间复杂度分析:第1行时间复杂度为O(1),2~3行时间复杂度为O(n),4~5行时间复杂度为O(1),6~9行时间复杂度为O(n),10~14行时间复杂度为O(n×half-sum),15~20行时间复杂度为O(1),21~26行时间复杂度为O(n),27~29行时间复杂度为O(1)。