习题8.1
6.切割木棍问题 为下列问题设计一个动态规划算法。已知小木棍的销售价格pi和长度i相关,i=1,2,…,n,如何把长度为n的木棍切割为若干根长度为整数的小木棍,使得所获得的总销售价格最大?该算法的时间效率和空间效率各是多少?
解答:令长度为n的木棍能获得的最大价格为profit[n],递推公式为:profit[n] = max(pi[i] + profit[length - seg[i]]), 其中i = 1,2,3,...n;边界条件profit[0]=0。
#include <iostream>
using namespace std; //自底向上,两个循环,不用递归;
int main()
{
int n = 10;
int price[11] = { 0, 1, 7, 8, 9, 10, 17, 17, 20, 23, 24 };
int *r = new int[n + 1];
for (int i = 0; i <= n; ++i)
r[i] = 0; //初始化
for (int i = 1; i <= n; ++i)//规模长度为i
{
int q = INT_MIN;
for (int j = 1; j <= i; ++j)//计算规模为i的最大收益
{
if (q < (price[j] + r[i - j]))//因为i>i-j,所以当计算r[i]时,r[i-j]已经解决,可以直接用
q = (price[j] + r[i - j]); //迭代q;
}
r[i] = q; //找出i这个位置的最优解;
}
cout << r[n]; //最后是n这个位置,就是n米长的木头的最大价值。
delete r;
return 0;
}
此算法的时间效率是O(n^2),空间效率是O (N)
7.最短路径数量 国际象棋中的车可以水平或竖直移到棋盘中同行或同列的任何一格。将车从棋盘的一角移到另一对角,有多少条最短路径?路径的长度由车所经过的方格数(包括第一格和最后一格)来度量。使用下列方法求解该问题。
a.动态规划算法
解答: 国际象棋的棋盘为8*8,假设从左下角移动到右上角,P(i,j)表示从起始位置移动到第i行第j列的最短路径数,递推公式为
计算结果如下图所示:
b.基本排列组合
解答:对于n*n的棋盘,从(1,1)移动到(n,n)的最短路径总数应该为C(2(n-1), n-1), 因为必走2(n-1)步,其中n-1步向左,剩下为向右。C(14,7)=3432
11.最大子方阵 对一个m×n布尔矩阵B,找出其元素均为0的最大子方阵。设计一个动态规划算法并给出时间效率。(该算法可能会用于在计算机屏幕中寻找最大空白区域或者是选择建筑地点。)
解答:对每个元素,把以其为右下角,元素全为0的正方形的最长边长记录下来。如果以元素B(i, j)为右下角的正方形边长为b,那么以B(i-1, j)为右下角的正方形边长肯定为b-1,且以B(i, j-1)为右下角的正方形边长为b-1,否则正方形的边不完整。
public int maximalSquare(char[][] a) {
if(a.length == 0) return 0;
int m = a.length, n = a[0].length, result = 0;
int[][] b = new int[m+1][n+1];
for (int i = 1 ; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if(a[i-1][j-1] == '0') {
b[i][j] = Math.min(Math.min(b[i][j-1] , b[i-1][j-1]), b[i-1][j]) + 1;
result = Math.max(b[i][j], result); // update result
}
}
}
return result*result;
}
习题8.2
5.假设n种物品中每种物品的数量不限,为该背包问题设计一个动态规划算法并分析该算法的时间效率。
解答:完全背包问题与01背包问题的区别在于每一件物品的数量都有无限个,而01背包每件物品数量只有一个。问题解法其实和01背包问题一样,只是初始化的值和递推公式需要稍微变化一下。初始化时,当只考虑一件物品a时,f[1][j] = j/weight[a]。递推公式计算时,f[i][j] = max{f[i-1][j], (f[i][j-weight[i]]+value[i])},注意这里当考虑放入一个物品 i 时应当考虑还可能继续放入 i,因此这里是f[i][j-weight[i]]+value[i], 而不是f[i-1][y-weight[i]]+value[i]。算法的时间效率θ(nW)
习题8.3
11.矩阵相乘 考虑如何使得在计算n个矩阵的乘积 时,总的乘法次数最小,这些矩阵的维度分别为
。假设所有两个矩阵的中间乘积都使用蛮力算法(基于定义)计算。
a.给出一个三个矩阵连乘的例子,当分别用 和
计算时,它们的乘法次数至少相差1000倍。
解答:矩阵维数A1为1000*1,A2为1*1000,A3为1000*1
b.有多少种不同的算法来计算n个矩阵的连乘乘积?
解答:算法数递推公式为. 并且m(1)=1.
c.设计一个求n个矩阵乘法最优次数的动态规划算法。
解答:设矩阵连乘积AiAi+1…Aj简记为A[i:j],设计算A[i:j],1≤i≤j≤n,所需要的最少数乘次数m[i,j],则原问题的最优值为m[1,n]。当i=j时,A[i:j]=Ai,因此,m[i][i]=0,i=1,2,…,n。当i<j时,若A[i:j]的最优次序在Ak和Ak+1之间断开,i<=k<j,则:m[i][j]=m[i][k]+m[k+1][j]+pi-1*pk*pj。由于在计算是并不知道断开点k的位置,所以k还未定。不过k的位置只有j-i个可能。因此,k是这j-i个位置使计算量达到最小的那个位置。
综上,有递推关系如下:
习题8.4
11.挑棍游戏 也叫“挑游戏棒”或“撒棒”。该游戏有若干塑料或木制的游戏棒散倒在桌子上,玩家要试着把他们一根接一根取走而不要移动其他游戏棒。在这里,我们只考虑一对对游戏棒之间是不是通过一系列相互搭着的游戏棒相连接。给定n(n>1)根游戏棒(假设它们散倒在一张很大的画图纸上)的端点列表,请找出左右相连的游戏棒。请注意,搭在一起的算相连,但能通过其他相连游戏棒间相连的也应该算相连。
解答:该任务初看跟Warshall算法没有联系,但仔细分析后发现,只要将游戏棒缩小成一个点,如果两根游戏棒的端点值一样,则可以看成这两个点之间有边相连;这样散倒在桌子上的游戏棒就变成了一个无向图,找出所有相连游戏棒的任务就变成了求出该无向图的传递闭包。