《算法导论》第16章 贪心算法 个人笔记
2017-06-01 12:59
148 查看
第16章 贪心算法
16.1 活动选择问题
问题:假设有一个n个活动的集合S=a1,a2,...,an,这些活动使用同一个资源,而这个资源在某个时刻只能供一个活动使用。每个活动都有一个开始时间si和一个结束时间fi。若si≥fi或sj≥fi,则ai和aj是兼容的。在活动选择问题中,我们希望选出一个最大兼容活动集。假设活动已按结束时间的单调递增顺序排序。1、动态规划法
令Sij表示在ai结束之后开始。且在aj开始之前结束的那些活动的集合,用c[i,j]表示集合Sij的最优解的大小,故有c[i,j]=0,ifSij=ϕc[i,j]=maxak∈Sijc[i,k]+c[h,j]+1,ifSij≠ϕ
2、贪心选择
定理:考虑任意非空子问题Sk,令am是Sk中结束时间最早的活动,则am在Sk的某个最大兼容活动子集中。证明:令Ak是Sk的一个最大兼容子集,且aj是Ak中结束时间最早的活动。
若aj=am,即证。
若aj≠am,将Ak中的aj替换为am,因为fm≤fj,则还是兼容的,数目不变,故替换后的也是Sk的一个最大兼容活动子集,且包含am。
- 递归贪心算法
为方便初始化,添加一个虚拟活动a0,其结束时间f0=0
public List<Integer> RECURSIV_ACTIVITY_SELECTOR(int[] s,int[] f,int k,int n){ int m = k + 1; while(m<=n && s[m]<=f[k]) m++; List<Integer> res = new ArrayList<>(); if(m<=n) return res.add(m).addAll(RECURSIV_ACTIVITY_SELECTOR(int[] s,int []f,int k,int n)) else return res; }
迭代贪心算法
public List<Integer> GREED_ACTIVITY_SELECTOR(int[] s,int[] f){ int n = s.length - 1; //去掉虚拟活动 List<Integer> res = new ArrayList<>(); res.add(1); int k = 1; for(int i = 2; i<=n; i++){ if(s[m]>=f[k]){ res.add(m); k = m; } } return res; }
16.2 贪心算法原理
一般地,我们按如下步骤设计贪心算法:1. 将最优化问题转化为这样的形式:对其做出一次选择后,只剩下一个子问题需要求解。
2. 证明做出贪心选择后,原问题总是存在最优解,即贪心选择总是安全的。
3. 证明做出贪心选择后,剩余的子问题满足性质:其最优解与贪心选择组合即可得到原问题的最优解,这样就得到了最优子结构。
贪心对动态规划
0-1背包问题:动态规划分数背包问题:贪心
/** * @param m 表示背包的最大容量 * @param n 表示商品个数 * @param w 表示商品重量数组 * @param p 表示商品价值数组 */ public static int[][] Package1(int m, int n, int[] w, int[] p) { //c[i][v]表示前i件物品恰放入一个重量为m的背包可以获得的最大价值 int c[][] = new int[n + 1][m + 1]; for (int i = 0; i < n + 1; i++) c[i][0] = 0; for (int j = 0; j < m + 1; j++) c[0][j] = 0; for (int i = 1; i < n + 1; i++) { for (int j = 1; j < m + 1; j++) { //当物品为i件重量为j时,如果第i件的重量(w[i-1])小于重量j时,c[i][j]为下列两种情况之一: //(1)物品i不放入背包中,所以c[i][j]为c[i-1][j]的值 //(2)物品i放入背包中,则背包剩余重量为j-w[i-1],所以c[i][j]为c[i-1][j-w[i-1]]的值加上当前物品i的价值 if (w[i - 1] <= j) { if (c[i - 1][j] < (c[i - 1][j - w[i - 1]] + p[i - 1])) c[i][j] = c[i - 1][j - w[i - 1]] + p[i - 1]; else c[i][j] = c[i - 1][j]; } else c[i][j] = c[i - 1][j]; } } return c; } //用一维数组存储 public static int Package2(int m, int n, int[] w, int[] p) { int[] f = new int[m + 1]; for (int i = 1; i < f.length; i++) //必装满则f[0]=0,f[1...m]都初始化为无穷小 f[i] = Integer.MIN_VALUE; for (int i = 0; i < n; i++) { for (int j = f.length - 1; j >= w[i]; j--) { f[j] = Math.max(f[j], f[j - w[i]] + p[i]); } } return f[m]; }
在具体运用时,可以首先假设全部物品装进背包是否超载,若不超载则直接输出最优解。有一次某公司一道笔试题就是这样,直接上dq就超时gg了=。=
16.3 赫夫曼编码
赫夫曼编码用于压缩数据,根据每个字符的出现频率构造最优二进制表示。前缀码:没有任何码字是其他码字的前缀。
构造赫夫曼编码,使用一个以属性freq为关键字的最小优先队列Q。
HUFFMAN(C) n = C.length Q = C for i =1 to n-1 allocate a new node z z.left = x = EXTRACT-MIN(Q) z.right = y = EXTRACT-MIN(Q) z.freq = x.freq + y.freq INSERT(Q,z) return EXTRACT-MIN(Q) //return the root of the tree
定理:过程HUFFMAN会生成一个最优前缀码。
相关文章推荐
- 算法导论学习笔记(十四):贪心算法(一):活动安排问题
- 算法导论 第16章 活动选择问题的递归和迭代贪心算法
- 《算法导论》第4章 分治策略 个人笔记
- 《算法导论》第9章 中位数和顺序统计量 个人笔记
- 《算法导论》第8章 线性时间排序 个人笔记
- 算法导论学习笔记——贪心算法
- 《算法导论》第15章 动态规划 个人笔记
- 算法导论_第16章_贪心算法_creatshare分享会
- 《算法导论》笔记(10)贪心算法 部分习题
- 《算法导论》第12章 二叉搜索树 个人笔记
- 算法导论第16章 贪心算法之活动选择
- 《算法导论》笔记 第16章 *16.4 贪心法的理论基础
- 《算法导论》笔记 第16章 16.3 赫夫曼编码
- 《算法导论》第2章 算法基础 个人笔记
- 算法导论-第16章-贪心算法-16.1 活动选择问题
- 《算法导论》读书笔记之第16章 贪心算法—活动选择问题
- 《算法导论》笔记 第16章 16.2 贪心策略的基本内容
- 《算法导论》笔记 第16章 总结与思考
- 《算法导论》第6章 堆排序 个人笔记
- 《算法导论》第13章 红黑树 个人笔记