贪心算法
2017-05-24 12:16
405 查看
贪心算法和动态规划有异曲同工之秒,能用贪心法的,就不用动规。我只想说,动态规划真TM难。
分数背包问题
Huffman编码
贪心算法这样一个算法,它在每一步都做出在当时看来是最优的方案,即它总是做出局部最优的选择。然后构成一个全局最优解。贪心算法也是一个强有力的算法,很多问题都能用贪心算法来解决。下面就说说两个经典的问题,分数背包问题和哈夫曼(Huffman)编码。
正如贪心算法一样,人总是贪的,如果真有这样一件事,我们当然希望全部拿走,但是奈何空间有限。为简单起见,假设所有数据都是整数,该问题的输入和输出如下所述:
输入:
第一行是一个整数m,表示商品的数量
第二行是m个整数,表示商品的价值
输出:
最大价值v
定义p = v / w,我们称之为性价比,很明显,我们当然应该取性价比最高的商品,即价值最高,体积最小。
比如一个体积为50的背包,有三件商品,体积和价值分别为
所以我们先取商品1, 价值为60, 占10体积,还剩40体积,再取商品2,价值为100, 占20体积,还剩20体积,最后取20体积商品3,价值为4 * 20 = 80, 所以最优方案是60 + 100 + 80 = 240. 代码如下所示:
输出结果如下:
哈夫曼编码就是一个贪心的过程,每次选择频率最小的两个数据,最终构成一棵哈夫曼树,过程如下:
初始状态,集合里是每个结点,首先选择「e」和「f」点,如下所示:
然后,构造一个结点,左右子树分别是这两个结点,结点的频率值为两者之和,如下所示:
重复上述过程,直至最终只有一个结点,如下所示:
从根结点开始,沿路径到根结点,左子树为0,右子树为1,即可得到各编码值。代码如下所示:
结果输出如下所示:
分数背包问题
Huffman编码
贪心算法这样一个算法,它在每一步都做出在当时看来是最优的方案,即它总是做出局部最优的选择。然后构成一个全局最优解。贪心算法也是一个强有力的算法,很多问题都能用贪心算法来解决。下面就说说两个经典的问题,分数背包问题和哈夫曼(Huffman)编码。
分数背包问题
分数背包问题是这样的,假设有一个背包体积为W, 有一系列商品,他们的体积各不相同,找出获取商品价值最大的方案。分数背包问题和0-1背包问题的惟一区别在于,是否可以取商品的一部分。贪心算法可以求解分数背包问题,但无法求解0-1背包问题。正如贪心算法一样,人总是贪的,如果真有这样一件事,我们当然希望全部拿走,但是奈何空间有限。为简单起见,假设所有数据都是整数,该问题的输入和输出如下所述:
输入:
第一行是一个整数m,表示商品的数量
第二行是m个整数,表示商品的价值
输出:
最大价值v
定义p = v / w,我们称之为性价比,很明显,我们当然应该取性价比最高的商品,即价值最高,体积最小。
比如一个体积为50的背包,有三件商品,体积和价值分别为
商品(i) | 1 | 2 | 3 |
体积(v) | 10 | 20 | 30 |
价值(w) | 60 | 100 | 120 |
性价比(p) | 6 | 5 | 4 |
#include <stdio.h> #include <string.h> #include <stdlib.h> typedef struct Objcect { int c; int v; double p; }Object; int compare(const void* n1, const void* n2) { return ((struct Objcect*)n2)->p - ((struct Objcect*)n1)->p; } int main(void) { int m, w; while(scanf("%d", &m), m) { struct Objcect* objs = (struct Objcect*)malloc(sizeof(struct Objcect) * m); for(int i = 0; i != m; ++i) { scanf("%d %d", &objs[i].c, &objs[i].v); objs[i].p = (double)objs[i].v / objs[i].c; } qsort(objs, m, sizeof(struct Objcect), compare); scanf("%d", &w); double value = 0; for(int i = 0; i != m && w != 0; ++i) { if(objs[i].c <= w) { value += objs[i].v; w -= objs[i].c; }else { value += w * objs[i].p; w = 0; } } printf("%.2lf\n", value); free(objs); } return 0; }
输出结果如下:
Huffman编码
哈夫曼编码的实用性还挺高的,可以有效的压缩数据,哈夫曼编码是这样的,假设有一个文件,其中每个字符都有一个使用频率,可以给每个字符构造一个编码,达到压缩文件的目的,如下所示:字符 | a | b | c | d | e | f |
频率 | 45 | 13 | 12 | 16 | 9 | 5 |
变长编码 | 0 | 101 | 100 | 111 | 1101 | 1100 |
初始状态,集合里是每个结点,首先选择「e」和「f」点,如下所示:
然后,构造一个结点,左右子树分别是这两个结点,结点的频率值为两者之和,如下所示:
重复上述过程,直至最终只有一个结点,如下所示:
从根结点开始,沿路径到根结点,左子树为0,右子树为1,即可得到各编码值。代码如下所示:
#include <stdio.h> #include <string.h> #include <stdlib.h> typedef struct Node { int freq; char letter; struct Node* leftChild; struct Node* rightChild; }Node; int nodeCompare(const void* node1, const void* node2) { return (*(struct Node**)node1)->freq - (*(struct Node**)node2)->freq; } struct Node* generateHuffman(int m) { struct Node* root = NULL; struct Node* List[m]; for(int i = 0; i != m; ++i) { struct Node* node = (struct Node*)malloc(sizeof(struct Node)); scanf("%s %d", &node->letter, &node->freq); node->leftChild = NULL; node->rightChild = NULL; List[i] = node; } //集合中共有多少个元素 int total = m; while(total > 1) { //按照频率高低进行排序 qsort(List, total, sizeof(struct Node*), nodeCompare); struct Node* node1 = (struct Node*)List[0]; struct Node* node2 = (struct Node*)List[1]; if(node1 && node2) { struct Node* node = (struct Node*)malloc(sizeof(struct Node)); node->letter = -1; node->freq = node1->freq + node2->freq; node->leftChild = node1; node->rightChild = node2; //删除第一、第二两个结点,其他元素前移 for(int i = 2; i != total; ++i) List[i - 2] = List[i]; //将最后一点加入到集合 List[total - 1] = NULL; List[total - 2] = node; --total; root = node; //修改根结点 } } return root; } //输出Huffman编码 //code,用于记录当前结点的编码值 void printHuffmanCode(struct Node* root, int* code) { //当前遍历结点索引 static int index = 0; if(root == NULL) return ; //如果是往左走,记录结点值为0 if(root->leftChild != NULL) { code[index++] = 0; printHuffmanCode(root->leftChild, code); } //如果是往右走,记录结点值为1 if(root->rightChild != NULL) { code[index++] = 1; printHuffmanCode(root->rightChild, code); } //如果是有效结点 if(root->letter != -1) { //输出当前字符 printf("%c : ", root->letter); //输出当前编码 for(int i = 0; i != index; ++i) printf("%d", code[i]); printf("\n"); } //指针回溯 code[--index] = -1; return ; } //递归删除Huffman树 void destroyTree(struct Node* root) { if(root->leftChild != NULL) destroyTree(root->leftChild); if(root->rightChild != NULL) destroyTree((root->rightChild)); free(root); root = NULL; return ; } int main(void) { int m; while(scanf("%d", &m) == 1) { if(m == 0) break; //构建Huffman树 struct Node* root = generateHuffman(m); int* code = (int*)malloc(sizeof(int) * m); memset(code, -1, sizeof(int) * m); printHuffmanCode(root, code); destroyTree(root); free(code); } return 0; }
结果输出如下所示:
相关文章推荐
- 1004贪心算法acm
- 贪心算法 Problem P 1015 求最少花费
- 贪心算法-1004
- 【算法】—-贪心算法(背包问题)
- ACM--贪心算法--活动安排问题二
- poj1700 贪心算法
- 贪心算法小白の人品测试
- 贪心算法 最优装载问题
- 2037 贪心算法(选择不相交的区间) 水题
- 基于贪心算法的几类区间覆盖问题
- 基于贪心算法的几类区间覆盖问题
- 贪心算法与动态规划的比较
- NYOJ 1057 寻找最大数(三)贪心算法
- POJ 3614(最小优先队列 + 贪心算法)
- 贪心算法的理解
- 贪心算法
- 算法导论第十六章贪心算法-思考题16-1找零问题
- 贪心算法----正整数分解问题 和相同,乘积最大
- hdu1789 简单贪心算法
- 1052 Tian Ji -- The Horse Racing 田忌赛马 贪心算法