算法导论第十五章

Posted Haruna_K

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法导论第十五章相关的知识,希望对你有一定的参考价值。

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)\)

以上是关于算法导论第十五章的主要内容,如果未能解决你的问题,请参考以下文章

算法导论:钢条切割

2019-2020-1 20191315《信息安全专业导论》第十一周学习总结

第十五章 加密算法实例1--注册登录(消息摘要算法)

第十五章 原子变量和非阻塞同步机制

Java第十五章Annotation注释

《信息安全专业导论》第十一周学习总结