算法导论第十五章
15.1
15.1-1
证明:
T(n) = 1+\(\sum_0^{n-1}T(j)\)
令S(n) = \(\sum_0^nT(j)\)
则S(n) - S(n-1) = 1 + S(n-1)
S(n) = \(2^{n+1}\)-1
T(n) = \(2^n\)
15.1-2
长度i | 1 | 2 | 3 | 4 |
---|---|---|---|---|
价格pi | 1 | 4 | 6.5 | 4 |
价格密度 | 1 | 2 | 6.5/3 | 1 |
按照贪心策略分割为3、1,总价格为7.5
然而最优解为2、2,总价格为8
15.1-3
#include <limits.h>
int *solution(int *p, int n, int c)
{
int r[n+1];
r[0] = 0;
for (int i = 1; i <=n; i++)
{
int q = INT_MIN;
for (int j = 1; j <= i; j++)
{
q = max(q, p[j]+r[i-j]-c);
}
r[i] = q;
}
return r;
}
15.1-4
#include <limits.h>
void MEMORIZED_CUT_ROD_AUX(int *p, int n, int *r, int *s)
{
if (r[n] >= 0)
{
return r[n];
}
if (n == 0) q = 0;
else
{
q = INT_MIN;
for (int i = 1; i <= n; i++)
{
int rest = MEMORIZED(p, n-i, r, s);
if (q < p[i] + rest)
{
q = p[i] + rest;
s[n] = i;
}
}
r[i] = q;
}
return q;
}
void MEMOIZED_CUT_ROD(int *p, int n)
{
int r[n+1];
for (int i = 0; i <= n; i++)
{
r[i] = INT_MIN;
}
int s[n+1];
return MEMORIZED_CUT_ROD_AUX(p, n, r, s);
}
15.1-5
int solution(int n)
{
int res[MAX_SIZE];
res[0] = 0;
res[1] = 1;
for (int i = 2; i <= n; i++)
{
res[i] = res[i-1]+res[i-2];
}
return res[n];
}
15.2
15.2-1
1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|
6 | 2040 | 1950 | 1770 | 1860 | 1500 | 0 |
5 | 1930 | 2430 | 930 | 3000 | 0 | |
4 | 405 | 330 | 180 | 0 | ||
3 | 330 | 360 | 0 | |||
2 | 150 | 0 | ||||
1 | 0 |
最优化括号方案:
(\(A_1\)\(A_2\))((\(A_3A_4\))(\(A_5A_6\)))
15.2-2
typedef struct
{
int matrix[MAX_SIZE][MAX_SIZE];
int n;
int m;
}Matrix;
Matrix MATRIX_CHAIN_MUTIPLY(Matrix *a, int **s, int front, int rear)
{
if (front == rear)
{
return a[front];
}
else
{
int p = s[front][rear];
Matrix t = MATRIX_CHAIN_MUTIPLY(a, s, front, p);
Matrix y = MATRIX_CHAIN_MUTIPLY(a, s, p+1, rear);
Matrix u;
u.n = t.n;
u.m = y.m;
for (int i = 0; i < t.n; i++)
{
for (int j = 0; j < t.m; j++)
{
for (int k = 0; k < t.m; k++)
{
u.matrix[i][k] += t.matrix[i][j]*y.matrix[j][k];
}
}
}
return u;
}
}
15.2-3
证明:
设P(k) >= \(c2^k\)
P(n) = \(\sum_1^{n-1}\)P(k)P(n-k)
\(\geq\)\(\sum_1^{n-1}c2^k*c2^{n-k}\)
\(\geq\)\(\sum_1^{n-1}c^22^n\)
\(\geq\)\(c2^n\)
15.2-4
\(\frac{n^2-n}{2}\)个顶点,2(n-2)条边,分别连接顶点(1, i)、(i+1, n)(i = 2,3,4,...,n-1)
15.2-5
由条件。只有计算m(a, b)(a<i, b=j或者a = i, b >j)时才会访问m(i, j)
所以R(i,j) = i-1+n-j = n+i-j-1(j > i)
所以\(\sum_1^n\)\(\sum_1^n\)R(i,j) = \(\frac{n^2-n}{2}\)\((n-1)\)+\(\sum_1^ni*(n-i)\)-\(\sum_2^{n-1}\)\(\frac{(n-j+1)(j+n)}{2}\)
= \(\frac{n^3-n}{3}\)
15.2-6
证明:
显然,当n=2时结论成立。
假设当n=k时结论也成立,
则当n=k+1时,
记\(N_k\)为n=k时的表达式,则\(N_{k+1} = (N_k*A_{k+1})\)
则n+1时,结论也成立。
15.3
15.3-1
第二种,原因:
显然A[1],...,A[n]的每一种排列都是一种可能的括号化方案,则T(n) = \(\Omega\)(n!)
而第二种T(n) = \(\Omega\)(\(\frac{4^n}{n^{3/2}}\)) < \(\Omega\)(n!)
15.3-2
因为MERGE_SORT在递归的每一步都生成全新的子问题
15.3-3
具有最优子结构的性质
15.3-4
输入序列为:<5,10,15,20>
根据Capulet的观点,
由于\(5*10*20\) < \(5*15*20\)
最优解为\(A_1(A_2A_3)\)
实际上最优解为\((A_1A_2)A_3\)
15.3-5
证明:只需举反例即可。
构造如下:将长度为x的钢条切割的最优解为k,x-k。
其中k与x-k的结构中都切割出长度为i的钢条至少\(\frac{l^i/2+1}{2}\)次。则与题目矛盾。
15.3-6
if \(c_k = 0\)
设\(W_{1,k}\)为从货币1兑换到货币k的最大收益。
则$W_{1,n} $ = \(max_{1\leq i \leq n-1}\){\(W_{1,i}*r_{i,n}\)}
由此递归式可求结果。
if \(c_k\)为任意值:
设\(L_{1,k}\)为从从货币1兑换到货币k由最大收益时的兑换次数
则$W_{1,n} $ = \(max_{1\leq i \leq n-1}\){\(W_{1,i}*r_{i,n}-c_{L_{1,i}+1}\)}
由于\(c_k\)的值不确定,无法确定是否具有最优子结构
若\(c_k\)是一个广义单调函数,则子问题仍具有最优子结构
15.4
15.4-1
i\j | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|
1 | 0 | 1 ! | 1 # | 1 ! | 1 ! | 1 # | 1 ! | 1 ! | 1 # |
0 | 1 ! | 1 @ | 2 ! | 2 # | 2 # | 2 ! | 2 # | 2 # | 2 ! |
0 | 1 ! | 1 @ | 2 ! | 2 @ | 2 @ | 3 ! | 3 # | 3 # | 3 ! |
1 | 1 @ | 2 ! | 2 # | 3 ! | 3 ! | 3 @ | 4 ! | 4 ! | 4 @ |
0 | 1 ! | 2 @ | 3 ! | 3 @ | 3 @ | 4 ! | 4 @ | 4 @ | 5 ! |
1 | 1 @ | 2 ! | 3 @ | 4 ! | 4 ! | 4 @ | 5 ! | 5 ! | 5 @ |
0 | 1 ! | 2 @ | 3 ! | 4 @ | 4 @ | 5 ! | 5 @ | 5 @ | 6 ! |
1 | 1 @ | 2 ! | 3 @ | 4 ! | 5 ! | 5 @ | 6 ! | 6 ! | 6 @ |
一个LCS:100110
15.2-4
void printLCS(int *c, char *s, char *t, int i, int j)
{
if (i == 0 or j == 0)
{
printf("\n");
return;
}
if (s[i] == t[j])
{
printf("%c ", s[i]);
}
else
{
if (c[i-1][j] >= c[i][j-1])
{
printLCS(c, s, t, i-1, j);
}
else
{
printLCS(c, s, t, i, j-1);
}
}
}
15.4-3
for (int i = 0; i <= s.size(); i++)
{
for (int j = 0; j <= t.size(); j++)
{
c[i][j] = 0;
}
}
void LCS_LENGTH(char *s, char *t, int *c, char *b, int i, int j)
{
if (i == 0 || j == 0)
{
return;
}
if (s[i-1] == t[j-1])
{
if (c[i-1][j-1] == 0)
LCS_LENGTH(s, t, c, b, i-1. j-1);
c[i][j] = c[i-1][j-1]+1;
b[i][j] = '!';
}
else
{
if (c[i-1][j] == 0)
LCS_LENGTH(s, t, c, b, i-1, j);
if (c[i][j-1] == 0)
LCS_LENGTH(s, t, c, b, i, j-1);
if (c[i-1][j] >= c[i][j-1])
{
b[i][j] = '@';
c[i][j] = c[i-1][j];
}
else
{
b[i][j] = '#';
c[i][j] = c[i][j-1];
}
}
}
15.4-4
int LCS_LENGTH(char *s, char *t)
{
m = s.length;
n = t.length;
if (m < n)
{
int tmp = m;
m = n;
n = m;
char *_tmp = s;
s = t;
t = _tmp;
}
int c[2][n+1];
for (int i = 0; i < 2; i++)
{
for (int j = 0; j <= n; j++)
{
c[i][j] = 0;
}
}
for (int i = 1; i <= m; i++)
{
for (int j = 1; j <= n; j++)
{
if (s[i-1] == t[j-1])
{
c[i%2][j] = c[(i-1)%2][j-1]+1;
}
else
{
c[i%2][j] = max(c[(i-1)%2][j], c[i%2][j-1]);
}
}
}
return c[m%2][n];
}
int LCS_LENGTH(char *s, char *t)
{
m = s.length;
n = t.length;
if (m < n)
{
int tmp = m;
m = n;
n = m;
char *_tmp = s;
s = t;
t = _tmp;
}
int c[n];
int temp = 0;
for (int i = 0; i < n; i++)
{
c[i] = 0;
}
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
if (s[i] == t[j])
{
int tmp = c[j];
c[j] = temp+1;
temp = tmp;
}
else
{
temp = c[j];
c[j] = max(c[j-1], c[j]);
}
}
}
return c[n-1];
}
15.4-5
void LONGEST_INCREASE_SEQUENCE(int *x, int *c, int *b)
{
int n = a.length();
int y[n];
for (int i = 0; i < n; i++) y[i] = x[i];
quick_sort(y, <);
LCS_LENGTH(x, y, c, b);
}
15.4-6
#include <limits.h>
int n = x.length();
int d[n];
int g[n];
for (int i = 0; i < n; i++)
{
g[i] = INT_MAX;
}
void LIS(int *x)
{
d[0] = 1;
g[d[0]] = x[0];
int length = 1;
for (int i = 1; i < n; i++)
{
int k = binary_search_geq(x, x[i]);
if (k == -1)
{
d[i] = d[i-1]+1;
g[d[i]] = x[i];
if (d[i] > length)
{
length = d[i];
}
}
else
{
d[i] = k;
g[k] = x[i];
if (d[i] > length)
{
length = d[i];
}
}
}
for (int i = 1; i <= length; i++)
{
printf("%d ", g[i]);
}
}
d[i]表示以x[i]为结尾的候选子序列的最长长度,g[i]表示最长长度为i的候选子序列的结尾元素。
由条件最长候选子序列的长度为\(max_{1\leq i \leq n}\){d[i]}
而g[i]满足题目中给出的提示,即g[i] < g[j] (i < j) ,且g[1],...,g[length]组成一个LIS
15.5
15.5-1
void CONSTRUCT_OPTIMAL_BST(int *root, int i, int j)
{
if (i > j)
{
return;
}
int q = root[i][j];
CONSRTUCT_OPTIMAL_BST(root, i, q-1);
printf("%d", q);
CONSTRUCT_OPTIMAL_BST(root, q+1, j);
}
15.5-2
0.06 | 0.28 | 0.64 | |||||
0.06 | 0.3 | 0.7 | |||||
0.06 | 0.32 | ||||||
0.06 | 0.24 | ||||||
0.05 | 0.3 | ||||||
0.05 | 0.32 | ||||||
0.05 | 0.34 | ||||||
0.05 |
0.06 | 0.16 | 0.28 | 0.42 | 0.49 | 0.64 | 0.81 | 1 |
0.06 | 0.18 | 0.32 | 0.39 | 0.54 | 0.71 | 0.9 | |
0.06 | 0.20 | 0.27 | 0.42 | 0.59 | 0.78 | ||
0.06 | 0.13 | 0.28 | 0.45 | 0.64 | |||
0.05 | 0.2 | 0.37 | 0.56 | ||||
0.05 | 0.22 | 0.41 | |||||
0.05 | 0.24 | ||||||
0.05 |
1 | 1 | |||||
---|---|---|---|---|---|---|
2 | 2 | |||||
3 | 3 | |||||
4 | 4 | |||||
5 | 5 | |||||
6 | 6 | |||||
7 |
use computer to solve it
15.5-3
时间复杂度为\(\Theta(n^4)\)
15.5-4
由于root[i,j-1] \(\leq\)root[i,j]\(\leq\)root[i+1,j]
所以for (r = i to j)减少为for (r = root[i,j-1] to root[i+1,j])为不大的一个常数次
实际上,root的值可以单独计算,而不是在最里层的循环中,
具体计算顺序为:沿着主对角线从左下向右上依次计算。
总计算次数为\(\sum_i\)\(\sum_j root[i+1][j]-root[i][j-1]+1\) = \(\sum_kroot[k,1]-root[1,k]+n-k\) = \(\Theta(n^2)\)