1. 程式人生 > >算法導論第十六章

算法導論第十六章

LG ted sum 不能 復雜度 selector else n-1 greedy

16.1

16.1-1

int c[n+1][n+1];
int b[n+1][n+1];
for (int i = 0; i <= n; i++)
{
  for (int j = 0; j <= n; j++)
  {
    c[i][j] = -1;
    b[i][j] = 0;
  }
}
void ACTIVITY_SELECTOR(int *s, int *f, int *c, int *b, int i, int j)
{
  if (c[i][j] != -1)    return;
  int flag = 0;
  for (int k = i+1; k < j; k++)
  {
    if
(s[k] >= f[i] && e[k] <= s[j]) flag = 1; } if (!flag) { c[i][j] = 0; } for (int k = i+1; k < j; k++) { ACTIVITY_SELECTOR(s, f, c, i, k); ACTIVITY_SELECTOR(s, f, c, k, j); res = c[i][k] + c[k][j] + 1; if (res > c[i][j]) { b[i][j] = k; c[i][j] = res; } } return
; }

將遞歸式改為叠代式可得,時間復雜度為\(\Theta(n^3)\)

而貪心策略的結果為\(\Theta(n)\)

16.1-2

struct Activity 
{
  int s;
  int f;
  bool operator < (const activity &other)
  {
    if (s < other.s)    return true;
    else return false;
  }
}
vector<int> GREEDY_SELECTOR(vector<Activity> activity)
{
  sort(activity.begin(), activity.end());
  vector<int
> res; int k = activity.size()-1; res.push_back(k); for (int m = k-1; m >= 1; m--) { if (activity[m].f <= activity[k].s) { res.push_back(m); k = m; } } return res; }

證明:

? 命題:對於任意非空子問題\(S_k\), 令\(a_m\)\(S_k\)中開始時間最晚的活動。則\(a_m\)\(S_k\)的某個最大兼容活動子集中。

? 令\(A_k\)\(S_k\)的一個最大兼容活動子集,且\(a_j\)是其中開始時間最晚的活動。若\(a_j = a_m\), 證畢。

? 否則,令\(A_{k‘}\) = (\(A_k\) - {\(a_j\)})||{\(a_m\)}(\(a_m開始時間晚於a_j\))

? 由於\(A_k\)中活動不相交,所以\(A_{k‘}\)中活動不相交。

? 又\(|A_k| = |A_{k‘}|\),

? 所以\(A_{k‘}\)也是\(S_k\)的一個最大兼容活動子集。


若貪心策略為選擇持續時間最短者、最早開始者等,均不能保證\(A_{k‘}\)兼容的性質

16.1-4

int *GREEDY_SOLUTION_ONE(int *s, int *f, bool *visited)
{
  int n = s.length();
  int a[n];
  for (int i = 1; i <= n; i++)
  {
    if (!visited[i])
    {
      a[0] = i;
      break;
    }
  }
  int cnt = 0;
  int k = a[0];
  for (int m = k+1; m <= n; m++)
  {
    if (s[m] >= f[k])
    {
      a[++cnt] = m;
      k = m;
       visited[m] = true;
    }
  }
  return a;
}
int GREEDY_SOLUTION_ONE(int *s, int *f)
{
  int n = s.length();
  bool visited[n+1];
  for (int i = 1; i <= n; i++)  visited[i] = false;
  int cnt = 0;
  while (n > 0)
  {
    int res[n];
    res = GREEDY_ACTIVITY_SELECTOR(s, f, visited);
    int len = res.length();
    for (int i = 0; i < len; i++)
    {
      visited[res[i]] = true;
    }
    n -= len;
    cnt++;
  }
  return cnt;
}

貪心策略:找出子問題的最大兼容活動子集塗上相同的顏色。

16.1-5

在輸入中添加哨兵:

\(activity = <a_0, a_1, ..., a_n, a_{n+1}>\)

其中\(a_0.start = 0, a_0.finish = 0\)

\(a_{n+1}.start\) = INT_MAX, \(a_{n+1}.finish\) = INT_MAX

#include <stdio.h>
#include <limits.h>
int n = s.length();
int _v[n+2][n+2];
int _e[n+2][n+2];
void solution(int *s, int *f, int *v)
{
  for (int i = 0; i <= n; i++)
  {
    _v[i][i+1] = 0;
  }
  for (int l = 2; l <= n+1; l++)
  {
    for (int i = 0; i <= n-l+1; i++)
    {
      j = i+l;
      int max = -1;
      for (int k = i+1; k < j; k++)
      {
        int temp = _v[i][k] + _v[k][j] + v[k];
        if (temp > max)
        {
          max = temp;
          _e[i][j] = k;
        }
      }
    }
  }
}

16.2

16.2-1

證明:

? 即證明命題:設\(a_k\)是剩余物品中\(v_i/w_i\) 最大的物品,則對於這個子問題,\(a_k\)必在最優解中。

? 證明:否則假設存在\(a_j\)\((w_j \leq w_k)\)使得\(\sum\)\(v_i\)更大

? 由於\(v_k/w_k \geq v_j/w_k\)

? 所以\(v_k \geq v_j\)

? 所以矛盾

16.2-2

typedef struct 
{
  int v;
  int w;
}Product;
bool CompareByW(Product a, Product b)
{
  return a.w < b.w;
}

int solution(vector<Product> products,  int weight)
{
  sort(products.begin(), products.end(), CompareByW);
  
  int e[weight+1];
  int p[weight+1];
  
  for (int i = 0; i <= weight; i++) e[i] = 0;
  
  for (int i = 1; i <= weight; i++)
  {
    for (int j = 0; weight - products[j].w >= 0; j++)
    {
      int temp = products[j].v + e[weight - products[j].w];
      if (temp > e[i])
      {
        e[i] = temp;
        p[i] = j;
      }
    }
  }
  
  return e[weight];
}

16.2-3

typedef struct 
{
  int v;
  int w;
}Product;
bool CompareByW(Product a, Product b)
{
  return a.w < b.w;
}
int solution(vector<int> products, int weight)
{
  sort(products.begin(), products.end(), CompareByW);
  
  int max = 0;
  int k = -1;
  for (int i = 0; i < products.size(); i++)
  {
    if ((weight = weight - products[i].w) >= 0)
    {
      max += products[i].v;
      int k = i;
    }
    else    break;
  }
  return max;
}       

證明:

? 設此貪心策略下裝入的商品按w遞增排序為\(p_1, p_2, ..., p_m\)

? 假設它不是最優解,則存在最優解下裝入的商品按w遞增排序為\(q_1, q_2, ..., q_{m‘}\)

? 由貪心的性質得:

? $\sum_{1\leq i \leq m} p_i.w $ \(\leq\) \(\sum_{1\leq i \leq m‘}q_i.w\)

? $\sum_{1\leq i \leq m} p_i.v $ \(\geq\) \(\sum_{1\leq i \leq m‘}q_i.v\)

? 矛盾

16.2-4

int solution(int *places, int m)
{
  int cnt = 0;
  int dis = 0;
  int n = places.length();
  for (int i = 0; i < n; i++)
  {
    dis += places[i];
    if (dis > m)
    {
      dis = 0;
      cnt++;
      i--;
    }
  }
  return cnt;
}

證明:

? 設此貪心策略下的補充水的地點依次為\(p_1, p_2, ..., p_m\)

假設它不是最優解,則存在最優解下的地點依次為$q_1, q_2, ..., q_{m‘}$

? 且\(m‘ < m\)

? 由於任意兩取水點之間距離\(dis \leq m\)

? 所以\(\sum _{1\leq i \leq m‘}\)\(dis(q_i)\) < \(\sum _{1\leq i \leq m}\)\(dis(p_i)\) = whole distance

? 矛盾

16.2-5

int solution(float *x)
{
  sort(x);
  int n = x.length();
  int pos[n];
  int cnt = 0;
  for (int i = 0; i < n; i++)
  {
    pos[cnt++] = i;
    float up = x[i]+1;
    while (y[i] <= up)
    {
      i++;
    }
  }
  return cnt;
}

證明:

? 最優子結構:

? 先對點集{x}得到{y}.\(S_{ij}\)表示以\(y_i\)為起點,\(y_j\)為最後一個點的單位長度區間集。設\(S_{mn}\)\(\subset\)\(S_{ij}\)

? 用c[i,j]表示集合\(S_{ij}\)的最優解大小。

? 則有遞歸式:

? c[i,j] = \(min_{S_{mn}\subset S_{ij}}\){c[i,m]+c[n,j]+1}

? 假設貪心策略下的結果[p1, p1+1], ..., [\(p_m, p_m+1\)]不是最優解,則存在最優解[q1, q1+1], ..., [\(q_{m‘}\), \(q_{m‘}+1\)]

? 且m‘ < m

? 又\(p_m+1 - p_1 \geq y_j - y_i\)\(p_{m-1}+1-p_1 < y_j - y_i\)

? 可知矛盾

16.2-6

typedef struct 
{
  int v;
  int w;
  float l;
}Product;
bool CompareByL(Product a, Product b)
{
  return a.l > b.l;
}
float solution(vector<product> products, int weight)
{
  sort(products.begin(), products.end(), CompareByL);
  int n = products.size():
  float max = 0;
  for (int i = 0; i < n; i++)
  {
    if (weight - products[i].w >= 0)
    {
      max += products[i].v;
      weight -= products[i].w;
    }
    else
    {
      max += products[i].l*weight;
      break;
    }
  }
  return max;
}

16.2-7

#include <cmath>
double solution(vector<int> a, vector<int> b)
{
  sort(a.begin(), a.end());
  sort(b.begin(), b.end());
  
  double max = 0;
  int n = a.size():
  for (int i = 0; i < n; i++)
  {
    max += pow(a[i], b[i]);
  }
  return max;
}

證明:

? \(lg\)\(\prod_1^n a_i^{b_i}\) = \(\sum_1^n b_ilga_i\)

? 由排序不等式可得,此算法正確。

16.4

16.4-1

證明:
? 1、S是一個有限集

? 2、\(I_k\)滿足遺傳性。

? 設任意集合B\(\subset\)A,|B| \(\leq\) k

? 對於任意A\(\subset\)B, 有A \(\subset\)\(I_k\)

? 3、滿足交換性

? 設\(A \in I_k 、B \in I_k, |A| < |B|\), 存在\(x \in B-A\) ,

? |{x} \(\bigcup A|\)\(\leq\)|B|

? 所以|x \(\bigcup\) A| \(\in\) \(I_k\)

16.4-2

證明:
? 1、S是一個有限集

? 2、\(I\)是可遺傳的

? 對於任意B\(\in I\)且A\(\subset\)B,有B中的列是線性無關的。

? 所以A中的列也是線性無關的,所以A\(\in I\)

? 3、\(M\)滿足交換性。

? 對於任意\(A \in I, B \in I, |A| < |B|\),則\(A \subset B\)

? 所以必存在某個元素\(x \in B-A\), 使得\(A \bigcup {x} \in I\)

16.4-3

證明:
? 1、S是一個有限集

? 2、\(I‘\)是可遺傳的

? 對於任意\(B‘ \in I‘且A‘ \subset B‘\), 存在最大獨立子集\(A \in I\), 使得\(A \subset S-B‘\)

? 又\(S-B‘ \subset S-A‘\)

? 所以\(A \subset S-A‘\)

? 3、\((S,I‘)\)是可交換的

? 對於任意\(A‘ \in I‘, B‘\in I‘, |A‘| < |B‘|\)

? 若\(A‘ \subset B‘\),由性質2得顯然成立。

? 否則,假設存在最大獨立子集\(C_1, C_2 \in I\),使得\(C_1 \subset S-A‘, C_2 \subset S-B‘\)

?

算法導論第十六章