【哈夫曼树】HDU 2527 Safe Or Unsafe

本文介绍了一道关于哈夫曼编码的应用题,通过计算给定字符串的哈夫曼编码长度来判断其是否超过预设的安全值。文章提供了一个详细的C++实现方案,包括输入输出流程、哈夫曼树构建过程及最终编码长度的计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题直通车HDU 2527 Safe Or Unsafe

Safe Or Unsafe

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1267    Accepted Submission(s): 496


Problem Description
Javac++ 一天在看计算机的书籍的时候,看到了一个有趣的东西!每一串字符都可以被编码成一些数字来储存信息,但是不同的编码方式得到的储存空间是不一样的!并且当储存空间大于一定的值的时候是不安全的!所以Javac++ 就想是否有一种方式是可以得到字符编码最小的空间值!显然这是可以的,因为书上有这一块内容--哈夫曼编码(Huffman Coding);一个字母的权值等于该字母在字符串中出现的频率。所以Javac++ 想让你帮忙,给你安全数值和一串字符串,并让你判断这个字符串是否是安全的?
 

Input
输入有多组case,首先是一个数字n表示有n组数据,然后每一组数据是有一个数值m(integer),和一串字符串没有空格只有包含小写字母组成!
 

Output
如果字符串的编码值小于等于给定的值则输出yes,否则输出no。
 

Sample Input
  
  
2 12 helloworld 66 ithinkyoucandoit
 

Sample Output
  
  
no yes
 
代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
typedef pair<int,int> pii;
const int maxn=1000005;
int f[maxn], num[27], fa[maxn], g[maxn];
char s[maxn];
struct cmp {
    bool operator()(const pii &t1,const pii &t2) {
        return t1.first>t2.first;
    }
};
int find_fa(int x) {
    if(fa[x]==x) return x;
    int ret=find_fa(fa[x]);
    g[x]+=g[fa[x]];
    return fa[x]=ret;
}
int main() {
    int T; scanf("%d",&T);
    while(T--) {
        for(int i=0; i<maxn; ++i) fa[i]=i;
        memset(num, 0, sizeof(num));
        memset(g, 0, sizeof(g));
        int n; scanf("%d%s",&n,s);
        int len=strlen(s);
        for(int i=0; i<len; ++i) num[s[i]-'a']++;
        priority_queue< pii, vector<pii>, cmp >M;
        int t=0, u=0;
        for(int i=0; i<26; ++i)
            if(num[i]) f[t]=num[i], M.push(make_pair(num[i],t++)), u++;
        int ans=(u==1?f[0]:0);
        while(!M.empty()) {
            pii rt=M.top(); M.pop();
            if(M.empty()) break;
            int x=rt.first, a=rt.second;
            rt=M.top(); M.pop();
            int y=rt.first, b=rt.second;
            fa[a]=fa[b]=t;
            f[t]=a+b, M.push(make_pair(x+y,t++));
        }
        for(int i=0; i<t; ++i) if(fa[i]!=i) g[i]++;
        for(int i=0; i<u; ++i) {
            find_fa(i);
            ans+=f[i]*g[i];
        }
        if(ans<=n) puts("yes");
        else puts("no");
    }
    return 0;
}




### Git 常用指令汇总 以下是基于提供的参考资料以及专业知识整理的 Git 常用命令列表: #### 初始化与配置 - **初始化仓库**: 使用 `git init` 可以在一个工作目录中初始化一个新的 Git 仓库[^1]。 - **全局用户名和邮箱设置**: ```bash git config --global user.name "Your Name" git config --global user.email "your_email@example.com" ``` #### 添加文件到暂存区 - 将单个文件添加到暂存区: ```bash git add filename ``` - 将多个文件添加到暂存区: ```bash git add *.extension ``` - 将所有更改的文件一次性添加到暂存区: ```bash git add . ``` #### 提交更改 - 提交暂存区中的更改并附带提交信息: ```bash git commit -m "commit message" ``` - 如果有已跟踪文件被修改过,则可以跳过暂存直接提交: ```bash git commit -am "commit message" ``` #### 查看状态与日志 - 查看当前工作树的状态,包括哪些文件已被修改但尚未提交: ```bash git status ``` - 显示所有的提交记录及其元数据: ```bash git log ``` - 更简洁的日志显示方式: ```bash git log --oneline ``` #### 分支管理 - 列出所有分支: ```bash git branch ``` - 创建新分支: ```bash git branch new_branch_name ``` - 切换至另一个分支: ```bash git checkout existing_branch_name ``` - 合并某个分支到当前分支: ```bash git merge source_branch_name ``` #### 远程操作 - 查看远程仓库的信息: ```bash git remote -v ``` - 添加一个新的远程仓库: ```bash git remote add shortname url ``` - 获取最新的远程分支更新: ```bash git fetch origin ``` - 将本地提交推送到远程仓库: ```bash git push origin master ``` #### 标签管理 - 查看已有标签: ```bash git tag ``` - 创建轻量级标签: ```bash git tag v1.0 ``` - 创建带有注解的标签: ```bash git tag -a v1.0 -m "Version 1 release" commit_hash ``` - 推送标签到远程仓库: ```bash git push origin v1.0 ``` - 删除本地标签: ```bash git tag -d v1.0 ``` - 删除远程标签: ```bash git push origin :refs/tags/v1.0 ``` #### 撤销操作 - 撤销最后一次提交但仍保留代码改动: ```bash git reset HEAD~1 ``` - 撤销某一次特定提交的历史记录而不影响后续提交: ```bash git revert commit_id ``` - 若想重置整个项目回到某一历史节点(危险操作),可使用硬重置: ```bash git reset --hard commit_id ``` #### 其他实用技巧 - 当前未保存的工作进度可以通过 stash 功能临时存储起来以便切换上下文环境: ```bash git stash save "message" git stash pop # 应用最新stash并移除它 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值