随手练——HDU Safe Or Unsafe (小根堆解决哈夫曼问题)

HDU 2527 :http://acm.hdu.edu.cn/showproblem.php?pid=2527

哈夫曼树,学完就忘得差不多了,题目的意思都没看懂,有时间复习下,看了别人的才知道是怎么回事。

贪心的题目,当总代价(要求最少)是由子代价累加或累乘出来,就可以考虑用哈夫曼来贪心。

题意: 就是给你一个字符串如:12 helloworld 统计出其中 d:1个,e:1个,h:1个,l:3个,o:2个,r:1个,w:1个,然后用一个数组保存起来a[7]={1,1,1,1,1,2,3};然后就是用哈夫曼树的思想求出新建的非叶子节点的权值之和:sum与12相比较如果sum小于等于12的话就输出yes否则输出no,此案例求出的sum = 27;所以输出no。

解题思路:

建立小根堆,每次拿出来两个,并调整,再把这两个的和插入进去,直到数组长度为0。

我觉得这样要比建树来的思路清晰很多,当然前提是了解堆。

#include <string>
#include <map>
#include <iostream>
using namespace std;

void heapify(int *a,int index ,int length) {
    while (index * 2 + 1 < length) {
        int left = index * 2 + 1;
        if (left + 1 < length&&a[left + 1] < a[left])left++;
        if (a[index] < a[left])break;
        swap(a[index], a[left]);
        index = left;

    }
}

void heapinsert(int *a,int index) {
    while (a[index] < a[(index - 1) / 2]) {
        swap(a[index], a[(index - 1) / 2]);
        index = (index - 1) / 2;
    }
}

int main() {
    int N;
    map<char, int>m;
    cin >> N;
    while (N--) {
        string str;
        int safe, res = 0;
        cin >> safe;
        cin >> str;
        for (int i = 0; i < str.length(); i++) {
            if (!m[str[i]]) m[str[i]] = 1;
            else m[str[i]]++;
        }
        int *a=new int[m.size()];
        int length = 0;
        for (map<char, int>::iterator it = m.begin(); it != m.end(); it++) {
            a[length++] = it->second;
        }
        for (int i = length / 2 - 1; i >= 0; i--) {
            heapify(a,i,length);
        }
        while (length > 0) {
            int m1 = a[0];
            swap(a[0], a[length - 1]);
            heapify(a, 0, --length);
            int m2 = a[0];
            swap(a[0], a[length - 1]);
            heapify(a, 0, --length);
            res += m1 + m2;
            if (length == 0)break;
            a[length] = m1 + m2;
            heapinsert(a,length++);
        }
        if (res <= safe) {
            cout << "yes" << endl;
        }
        else {
            cout << "no" << endl;
        }
        m.clear();
    }
}

原文地址:https://www.cnblogs.com/czc1999/p/10356630.html

时间: 2024-10-17 17:36:15

随手练——HDU Safe Or Unsafe (小根堆解决哈夫曼问题)的相关文章

scala写算法-用小根堆解决topK

topK问题是指从大量数据中获取最大(或最小)的k个数,比如从全校学生中寻找成绩最高的500名学生等等. 本问题可采用小根堆解决.思路是先把源数据中的前k个数放入堆中,然后构建堆,使其保持堆序(可以简单的看成k次insert操作).然后从源数据中的第k个数据之后的每个元素与堆的根节点(小根堆得root是最小的)比较,如果小于root,那么直接pass;如果大于,则执行headp.deleteMin,然后把该元素插入堆中并再次保持堆序.保持堆序需要涉及上滤与下滤的过程. 样例为: object M

数据结构(三):非线性逻辑结构-特殊的二叉树结构:堆、哈夫曼树、二叉搜索树、平衡二叉搜索树、红黑树、线索二叉树

在上一篇数据结构的博文<数据结构(三):非线性逻辑结构-二叉树>中已经对二叉树的概念.遍历等基本的概念和操作进行了介绍.本篇博文主要介绍几个特殊的二叉树,堆.哈夫曼树.二叉搜索树.平衡二叉搜索树.红黑树.线索二叉树,它们在解决实际问题中有着非常重要的应用.本文主要从概念和一些基本操作上进行分类和总结. 一.概念总揽 (1) 堆 堆(heap order)是一种特殊的表,如果将它看做是一颗完全二叉树的层次序列,那么它具有如下的性质:每个节点的值都不大于其孩子的值,或每个节点的值都不小于其孩子的值

数据结构第三部分:树与树的表示、二叉树及其遍历、二叉搜索树、平衡二叉树、堆、哈夫曼树、集合及其运算

参考:浙大数据结构(陈越.何钦铭)课件 1.树与树的表示 什么是树? 客观世界中许多事物存在层次关系 人类社会家谱 社会组织结构 图书信息管理 分层次组织在管理上具有更高的效率! 数据管理的基本操作之一:查找(根据某个给定关键字K,从集合R 中找出关键字与K 相同的记录).一个自然的问题就是,如何实现有效率的查找? 静态查找:集合中记录是固定的,没有插入和删除操作,只有查找 动态查找:集合中记录是动态变化的,除查找,还可能发生插入和删除 静态查找——方法一:顺序查找(时间复杂度O(n)) int

【数据结构】树与树的表示、二叉树存储结构及其遍历、二叉搜索树、平衡二叉树、堆、哈夫曼树与哈夫曼编码、集合及其运算

1.树与树的表示 什么是树? 客观世界中许多事物存在层次关系 人类社会家谱 社会组织结构 图书信息管理 分层次组织在管理上具有更高的效率! 数据管理的基本操作之一:查找(根据某个给定关键字K,从集合R 中找出关键字与K 相同的记录).一个自然的问题就是,如何实现有效率的查找? 静态查找:集合中记录是固定的,没有插入和删除操作,只有查找 动态查找:集合中记录是动态变化的,除查找,还可能发生插入和删除 静态查找--方法一:顺序查找(时间复杂度O(n)) int SequentialSearch(St

堆和哈夫曼树

堆分为最小堆和最大堆.最小堆指的是任意一个节点都有小于他的做儿子和右儿子.最大堆指的是任意一个节点大于打的左儿子右儿子. 最大堆的操作(堆得主要操作就是上滤和下滤) 插入:先将一个节点插入到堆得最后的位置然后上滤,如果他的父亲小于他,就把他父亲的值给他,继续循环,当退出循环的时候就是要插入的节点: 删除:删除堆顶元素,然后把最后一个元素拿上来做下滤:如果他的左右儿子中最大的那个大于他就把左右儿子中最大的那个值给堆顶,然后把左右儿子中最大的那个当做父节点继续循环,当循环退出的时候就是要插入的节点.

数据结构-并查集和堆、哈夫曼树

一.并查集的定义 并查集是一种维护集合的数据结构,它的名字中"并"."查"."集".分别取自Union(合并).Find(查找).Set(集合). 合并:就是合并两个集合 查找:判断两个元素是否在一个集合 那么并查集是用什么实现的,就是一个数组, 对于同一个集合来说只存在一个根结点,且将其作为所属集合的标识. 二.并查集的基本操作 初始化,每个元素都是一个独立的集合,因此需要令所有的father[i] = i; for(int i = 1; i

随手练——HDU 1237 表达式求值(输入格式典型)

坑了老子半天,结果是 float 范围不够!!! 基本思想: 将当前符号与栈顶符号进行对比,如果当前符号优先级小于栈顶符号,数字栈弹出两个数进行栈顶符号运算,继续和当前栈顶符号比较,直到当前符号优先级大于栈顶符号,再将当前元素入栈. 符号栈初始放置一个'#',并规定 '#',优先级低于任何符号. 表达式求值是老问题了,但是之前做的也不太完善,很多小地方还是没注意到,WA了好几次. 1. 终止条件,if (s.length() == 1 && s[0] == '0') break; 否则0+

随手练——HDU 1251 统计难题

知识点:前缀树 典型的前缀树模板. 这个版本要注意的是编译器选择C++可以AC,用G++就超内存了. #include <iostream> #include <malloc.h> #include <string> using namespace std; typedef struct node{ int pass; struct node* next[26]; } *trieTree; trieTree init() { trieTree t = (trieTree

随手练——数独 HDU - 5547 坑!坑!坑!

题目链接:HDU-5547 http://acm.hdu.edu.cn/showproblem.php?pid=5547 解题思想:随手练-- 数独 POJ - 2676 (回溯法+DFS) HDU 的这题实在是太坑了,M 数组开成 int 就过不了,改成 char 就过了.对着别人AC的代码,一点点试,到最后才试出来,数组的问题,但是不能理解啊,什么鬼,这也错?? 然后发现题目描述里有一句:Each test case starts with an empty line followed by