算法導論第十五章


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM