Advertisement

《趣学算法》第2章 贪心算法 读书笔记

阅读量:

14天阅读挑战赛

算法知识点——贪心算法 2.1

贪心算法:局部最优,而非整体最优

  • 贪心选择性质:

整体最优解能通过一系列局部最优的选择得到,选择依赖于已做出的选择而不依赖未做出的选择,无回溯过程。

  • 最优子结构性质:

问题的最优解包含其子问题的最优解。

算法题目——最优装载问题(p37)2.2&2.3

背包问题:物品可分割的装载问题。

0-1背包问题:物品不可分割的装载问题——不具有贪心选择性质,一系列局部最优选择得到最优解的近似解。

总重量一定,装载数量最大:局部最优=全局最优。(优先取重量小)

总重量一定,价值最大,可分割:局部最优=全局最优。(优先取性价比高)

总重量一定,价值最大,不可分割:局部最优不等于全局最优。

算法题目——会议安排问题 2.4

目标:在有限时间内召开尽可能多的会议。

贪心策略:每次从剩下会议中选择最早结束时间(最早开始时间+最短持续时间)且与已安排会议相容的会议安排。

代码:

复制代码
>       1. #include <iostream>

>  
>       2. #include <algorithm>
>  
>       3. #include <cstring>
>  
>       4. using namespace std;
>  
>       5. struct Meet
>  
>       6. {
>  
>       7.     int beg;
>  
>       8.     int end;
>  
>       9.     int num;
>  
>       10. } meet[1000];
>  
>       11. class setMeet
>  
>       12. {
>  
>       13. public:
>  
>       14.     void init();
>  
>       15.     void solve();
>  
>       16.  
>  
>       17. private:
>  
>       18.     int n, ans;
>  
>       19. };
>  
>       20. void setMeet::init()
>  
>       21. {
>  
>       22.     int s, e;
>  
>       23.     cout << "输入会议总数" << endl;
>  
>       24.     cin >> n;
>  
>       25.     int i;
>  
>       26.     cout << "输入会议开始时间和结束时间,以空格分开:" << endl;
>  
>       27.     for (i = 0; i < n; i++)
>  
>       28.     {
>  
>       29.         cin >> s >> e;
>  
>       30.         meet[i].beg = s;
>  
>       31.         meet[i].end = e;
>  
>       32.         meet[i].num = i + 1;
>  
>       33.     }
>  
>       34. }
>  
>       35. bool cmp(Meet x, Meet y)
>  
>       36. {
>  
>       37.     if (x.end == y.end)
>  
>       38.         return x.beg > y.beg;
>  
>       39.     return x.end < y.end;
>  
>       40. }
>  
>       41. void setMeet::solve()
>  
>       42. {
>  
>       43.     sort(meet, meet + n, cmp);
>  
>       44.     cout << "排完序的会议时间如下:" << endl;
>  
>       45.     int i;
>  
>       46.     cout << "会议编号 开始时间 结束时间" << endl;
>  
>       47.     for (i = 0; i < n; i++)
>  
>       48.         cout << " " << meet[i].num << "\t" << meet[i].beg << "\t" << meet[i].end << endl;
>  
>       49.     cout << "---------------------------------------" << endl;
>  
>       50.     cout << "选择的会议的过程:" << endl;
>  
>       51.     cout << " 选择第" << meet[0].num << "个会议" << endl;
>  
>       52.     ans = 1;
>  
>       53.     int last = meet[0].end;
>  
>       54.     for (i = 1; i < n; ++i)
>  
>       55.     {
>  
>       56.         if (meet[i].beg >= last)
>  
>       57.         {
>  
>       58.             ans++;
>  
>       59.             last = meet[i].end;
>  
>       60.             cout << " 选择第" << meet[i].num << "个会议" << endl;
>  
>       61.         }
>  
>       62.     }
>  
>       63.     cout << "最多可以安排" << ans << "个会议" << endl;
>  
>       64. }
>  
>       65. int main()
>  
>       66. {
>  
>       67.     setMeet sm;
>  
>       68.     sm.init();
>  
>       69.     sm.solve();
>  
>       70.     return 0;
>  
>       71. }
>  
>  
>  
>  
> ```
>
>
>
> 样例输入:  
>  10  
>  3 6  
>  1 4  
>  5 7  
>  2 5  
>  5 9  
>  3 8  
>  8 11  
>  6 10  
>  8 12  
>  12 14
>
>
>
>
>
> 样例输出:  
>  排完序的会议时间如下:  
>  会议编号 开始时间 结束时间  
>  2 1 4  
>  4 2 5  
>  1 3 6  
>  3 5 7  
>  6 3 8  
>  5 5 9  
>  8 6 10  
>  7 8 11  
>  9 8 12  
>  10 12 14  
>  \---------------------------------------  
>  选择的会议的过程:  
>  选择第2个会议  
>  选择第3个会议  
>  选择第7个会议  
>  选择第10个会议  
>  最多可以安排4个会议
>
>

### 算法题目——最短路径问题 Dijkstra 2.5

>
复制代码
  1. #include <cstdio>
复制代码
  2. #include <iostream>

  3. #include <cstring>

  4. #include <windows.h>

  5. #include <stack>

  6. using namespace std;

  7. const int N = 100;

  8. const int INF = 1e7;

  9. int map[N][N], dist[N], p[N], n, m;

  10. bool flag[N];

  11. void Dijkstra(int u)

  12. {

  13.     for (int i = 1; i <= n; i++)

  14.     {

  15.         dist[i] = map[u][i];

  16.         flag[i] = false;

  17.         if (dist[i] == INF)

  18.             p[i] = -1;

  19.         else

  20.             p[i] = u;

  21.     }

  22.     dist[u] = 0;

  23.     flag[u] = true;

  24.     for (int i = 1; i <= n; i++)

  25.     {

  26.         int temp = INF, t = u;

  27.         for (int j = 1; j <= n; j++)

  28.             if (!flag[j] && dist[j] < temp)

  29.             {

  30.                 t = j;

  31.                 temp = dist[j];

  32.             }

  33.         if (t == u)

  34.             return;

  35.         flag[t] = true;

  36.         for (int j = 1; j <= n; j++)

  37.             if (!flag[j] && map[t][j] < INF)

  38.                 if (dist[j] > (dist[t] + map[t][j]))

  39.                 {

  40.                     dist[j] = dist[t] + map[t][j];

  41.                     p[j] = t;

  42.                 }

  43.     }

  44. }

  45. void findpath(int u)

  46. {

  47.     int x;

  48.     stack<int> s;

  49.     cout << "源点为:" << u << endl;

  50.     for (int i = 1; i <= n; i++)

  51.     {

  52.         x = p[i];

  53.         while (x != -1)

  54.         {

  55.             s.push(x);

  56.             x = p[x];

  57.         }

  58.         cout << "源点到其他各顶点最短路径为:";

  59.         while (!s.empty())

  60.         {

  61.             cout << s.top() << "--";

  62.             s.pop();

  63.         }

  64.         cout << i << ";最短举例为:" << dist[i] << endl;

  65.     }

  66. }

  67. int main()

  68. {

  69.     int u, v, w, st;

  70.     system("color 0d");

  71.     cout << "请输入城市的个数:" << endl;

  72.     cin >> n;

  73.     cout << "请输入城市之间路线的个数:" << endl;

  74.     cin >> m;

  75.     cout << "请输入城市之间的路线和距离:" << endl;

  76.     for (int i = 1; i <= n; i++)

  77.         for (int j = 1; j <= n; j++)

  78.             map[i][j] = INF;

  79.     while (m--)

  80.     {

  81.         cin >> u >> v >> w;

  82.         map[u][v] = min(map[u][v], w);

  83.     }

  84.     cout << "请输入小明所在的位置:" << endl;

  85.     cin >> st;

  86.     Dijkstra(st);

  87.     cout << "小明所在的位置:" << st << endl;

  88.     for (int i = 1; i <= n; i++)

  89.     {

  90.         cout << "小明:" << st << " - "

  91.              << "要去的位置:" << i << endl;

  92.         if (dist[i] == INF)

  93.             cout << "sorry,无路可达" << endl;

  94.         else

  95.             cout << "最短距离为:" << dist[i] << endl;

  96.     }

  97.     findpath(st);

  98.     return 0;

  99. }
复制代码
输入:



请输入城市的个数:  
 5  
 请输入城市之间路线的个数:  
 11  
 请输入城市之间的路线和距离:  
 1 5 12  
 5 1 8  
 1 2 16  
 2 1 29  
 5 2 32  
 2 4 13  
 4 2 27  
 1 3 15  
 3 1 21  
 3 4 7  
 4 3 19  
 请输入小明所在的位置:  
 5





输出:  
 小明所在的位置:5  
 小明:5 - 要去的位置:1  
 最短距离为:8  
 小明:5 - 要去的位置:2  
 最短距离为:24  
 小明:5 - 要去的位置:3  
 最短距离为:23  
 小明:5 - 要去的位置:4  
 最短距离为:30  
 小明:5 - 要去的位置:5  
 最短距离为:0



源点为:5  
 源点到其他各顶点最短路径为:5--1;最短举例为:8  
 源点到其他各顶点最短路径为:5--1--2;最短举例为:24  
 源点到其他各顶点最短路径为:5--1--3;最短举例为:23  
 源点到其他各顶点最短路径为:5--1--3--4;最短举例为:30  
 源点到其他各顶点最短路径为:5;最短举例为:0

算法题目——哈夫曼编码 2.6

目标:以字符的使用频率为权重构建哈夫曼树,利用哈夫曼树对字符编码。将要编码的字符作为叶子结点,使用频率作为叶子结点的权值。权值越大的叶子离根越近。

贪心策略:每次从树的集合中取出没有双亲且权值最小的两棵左右子树。

代码:

复制代码
>       1. #include <iostream>

>  
>       2. #include <algorithm>
>  
>       3. #include <cstring>
>  
>       4. #include <cstdlib>
>  
>       5. using namespace std;
>  
>       6. #define MAXBIT 100
>  
>       7. #define MAXVALUE 10000
>  
>       8. #define MAXLEAF 30
>  
>       9. #define MAXNODE MAXLEAF * 2 - 1
>  
>       10. typedef struct
>  
>       11. {
>  
>       12.     double weight;
>  
>       13.     int parent;
>  
>       14.     int lchild;
>  
>       15.     int rchild;
>  
>       16.     char value;
>  
>       17. } HNodeType;
>  
>       18. typedef struct
>  
>       19. {
>  
>       20.  
>  
>       21.     int bit[MAXBIT];
>  
>       22.     int start;
>  
>       23. } HCodeType;
>  
>       24. HNodeType HuffNode[MAXNODE];
>  
>       25. HCodeType HuffCode[MAXLEAF];
>  
>       26. void HuffmanTree(HNodeType HuffNode[MAXNODE], int n)
>  
>       27. {
>  
>       28.     int i, j, x1, x2;
>  
>       29.     double m1, m2;
>  
>       30.     for (i = 0; i < 2 * n - 1; i++)
>  
>       31.     {
>  
>       32.         HuffNode[i].weight = 0;
>  
>       33.         HuffNode[i].parent = -1;
>  
>       34.         HuffNode[i].lchild = -1;
>  
>       35.         HuffNode[i].rchild = -1;
>  
>       36.     }
>  
>       37.     for (i = 0; i < n; i++)
>  
>       38.     {
>  
>       39.         cout << "Please input value and weight of leaf node " << i + 1 << endl;
>  
>       40.         cin >> HuffNode[i].value >> HuffNode[i].weight;
>  
>       41.     }
>  
>       42.     for (i = 0; i < n - 1; i++)
>  
>       43.     {
>  
>       44.         m1 = m2 = MAXVALUE;
>  
>       45.         x1 = x2 = 0;
>  
>       46.         for (j = 0; j < n + i; j++)
>  
>       47.         {
>  
>       48.             if (HuffNode[j].weight < m1 && HuffNode[j].parent == -1)
>  
>       49.             {
>  
>       50.                 m2 = m1;
>  
>       51.                 x2 = x1;
>  
>       52.                 m1 = HuffNode[j].weight;
>  
>       53.                 x1 = j;
>  
>       54.             }
>  
>       55.             else if (HuffNode[j].weight < m2 && HuffNode[j].parent == -1)
>  
>       56.             {
>  
>       57.                 m2 = HuffNode[j].weight;
>  
>       58.                 x2 = j;
>  
>       59.             }
>  
>       60.         }
>  
>       61.         HuffNode[x1].parent = n + i;
>  
>       62.         HuffNode[x2].parent = n + i;
>  
>       63.         HuffNode[n + i].weight = m1 + m2;
>  
>       64.         HuffNode[n + i].lchild = x1;
>  
>       65.         HuffNode[n + i].rchild = x2;
>  
>       66.         cout << "x1.weight and x2.weight in round " << i + 1 << "\t" << HuffNode[x1].weight << "\t" << HuffNode[x2].weight << endl;
>  
>       67.     }
>  
>       68. }
>  
>       69. void HuffmanCode(HCodeType HuffCode[MAXLEAF], int n)
>  
>       70. {
>  
>       71.     HCodeType cd;
>  
>       72.     int i, j, c, p;
>  
>       73.     for (i = 0; i < n; i++)
>  
>       74.     {
>  
>       75.         cd.start = n - 1;
>  
>       76.         c = i;
>  
>       77.         p = HuffNode[c].parent;
>  
>       78.         while (p != -1)
>  
>       79.         {
>  
>       80.             if (HuffNode[p].lchild == c)
>  
>       81.                 cd.bit[cd.start] = 0;
>  
>       82.             else
>  
>       83.                 cd.bit[cd.start] = 1;
>  
>       84.             cd.start--;
>  
>       85.             c = p;
>  
>       86.             p = HuffNode[c].parent;
>  
>       87.         }
>  
>       88.         for (j = cd.start + 1; j < n; j++)
>  
>       89.             HuffCode[i].bit[j] = cd.bit[j];
>  
>       90.         HuffCode[i].start = cd.start;
>  
>       91.     }
>  
>       92. }
>  
>       93. int main()
>  
>       94. {
>  
>       95.     int i, j, n;
>  
>       96.     cout << "Please input n: " << endl;
>  
>       97.     cin >> n;
>  
>       98.     HuffmanTree(HuffNode, n);
>  
>       99.     HuffmanCode(HuffCode, n);
>  
>       100.     for (i = 0; i < n; i++)
>  
>       101.     {
>  
>       102.         cout << HuffNode[i].value << ": Huffman code is: ";
>  
>       103.         for (j = HuffCode[i].start + 1; j < n; j++)
>  
>       104.             cout << HuffCode[i].bit[j];
>  
>       105.         cout << endl;
>  
>       106.     }
>  
>       107.     return 0;
>  
>       108. }
>  
>  
>  
>  
> ```
>
>
>
> 样例输入:  
>  Please input n:  
>  6  
>  Please input value and weight of leaf node 1  
>  a 0.05  
>  Please input value and weight of leaf node 2  
>  b 0.32  
>  Please input value and weight of leaf node 3  
>  c 0.18  
>  Please input value and weight of leaf node 4  
>  d 0.07  
>  Please input value and weight of leaf node 5  
>  e 0.25  
>  Please input value and weight of leaf node 6  
>  f 0.13  
>  
>
>
>
> 样例输出:
>
>
>
> x1.weight and x2.weight in round 1 0.05 0.07  
>  x1.weight and x2.weight in round 2 0.12 0.13  
>  x1.weight and x2.weight in round 3 0.18 0.25  
>  x1.weight and x2.weight in round 4 0.25 0.32  
>  x1.weight and x2.weight in round 5 0.43 0.57  
>  a: Huffman code is: 1000  
>  b: Huffman code is: 11  
>  c: Huffman code is: 00  
>  d: Huffman code is: 1001  
>  e: Huffman code is: 01  
>  f: Huffman code is: 10
>
>

### 算法题目——最小生成树求解问题 2.7

>
>
> 目标:对于n个顶点的连通图,找出n-1条最小且无回路的边。
>
>
>
> 子图:从原图中选中一些顶点和边组成的图。
>
>
>
> 生成子图:选中一些边和所有顶点组成的图。
>
>
>
> 生成树:生成子图是树。
>
>
>
> 最小生成树:权值之和最小的生成树。
>
>
>
> 贪心策略:避圈法。把已在生成树中的结点看作一个集合U,剩下的看作另一个集合V-U,从连接两个集合的边中选择一条权值最小的边。
>
>
>
> 代码:
>
>
复制代码
  1. #include <iostream>
复制代码
  2. using namespace std;

  3. const int INF = 0x3fffffff;

  4. const int N = 100;

  5. bool s[N];

  6. int closest[N];

  7. int lowcost[N];

  8. void Prim(int n, int u0, int c[N][N])

  9. {

  10.     s[u0] = true;

  11.     int i;

  12.     int j;

  13.     for (i = 1; i <= n; i++)

  14.     {

  15.         if (i != u0)

  16.         {

  17.             lowcost[i] = c[u0][i];

  18.             closest[i] = u0;

  19.             s[i] = false;

  20.         }

  21.         else

  22.             lowcost[i] = 0;

  23.     }

  24.     for (i = 1; i <= n; i++)

  25.     {

  26.         int temp = INF;

  27.         int t = u0;

  28.         for (j = 1; j <= n; j++)

  29.         {

  30.             if ((!s[j]) && (lowcost[j] < temp))

  31.             {

  32.                 t = j;

  33.                 temp = lowcost[j];

  34.             }

  35.         }

  36.         if (t == u0)

  37.             break;

  38.         s[t] = true;

  39.         for (j = 1; j <= n; j++)

  40.         {

  41.             if ((!s[j]) && (c[t][j] < lowcost[j]))

  42.             {

  43.                 lowcost[j] = c[t][j];

  44.                 closest[j] = t;

  45.             }

  46.         }

  47.     }

  48. }

  49. int main()

  50. {

  51.     int n, c[N][N], m, u, v, w;

  52.     int u0;

  53.     cout << "输入结点数n和边数m:" << endl;

  54.     cin >> n >> m;

  55.     int sumcost = 0;

  56.     for (int i = 1; i <= n; i++)

  57.         for (int j = 1; j <= n; j++)

  58.             c[i][j] = INF;

  59.     cout << "输入结点数u,v和边值w:" << endl;

  60.     for (int i = 1; i <= m; i++)

  61.     {

  62.         cin >> u >> v >> w;

  63.         c[u][v] = c[v][u] = w;

  64.     }

  65.     cout << "输入任一结点u0:" << endl;

  66.     cin >> u0;

  67.     Prim(n, u0, c);

  68.     cout << "数组lowcost的内容为:" << endl;

  69.     for (int i = 1; i <= n; i++)

  70.         cout << lowcost[i] << " ";

  71.     cout << endl;

  72.     for (int i = 1; i <= n; i++)

  73.         sumcost += lowcost[i];

  74.     cout << "最小的花费是:" << sumcost

  75.          << endl;

  76.     return 0;

  77. }
复制代码
样例输入:  
 输入结点数n和边数m:  
 7 12  
 输入结点数u,v和边值w:  
 1 2 23  
 1 6 28  
 1 7 36  
 2 3 20  
 2 7 1  
 3 4 15  
 3 7 4  
 4 5 3  
 4 7 9  
 5 6 17  
 5 7 16  
 6 7 25  
 输入任一结点u0:  
 1  
 



样例输出:



数组lowcost的内容为:  
 0 23 4 9 3 17 1  
 最小的花费是:57

全部评论 (0)

还没有任何评论哟~