PTA:7-88 哈夫曼编码 (30分)(优先队列,AC代码+解析)

7-88 哈夫曼编码 (30分)

在这里插入图片描述
输入样例:

7
A 1 B 1 C 1 D 3 E 3 F 6 G 6
4
A 00000
B 00001
C 0001
D 001
E 01
F 10
G 11
A 01010
B 01011
C 0100
D 011
E 10
F 11
G 00
A 000
B 001
C 010
D 011
E 100
F 101
G 110
A 00000
B 00001
C 0001
D 001
E 00
F 10
G 11

输出样例:

Yes
Yes
No
No
思路:

1. 根据输入,将字符出现的频率,加入优先队列(从小到大)中,方便后面计算。并使用map对字符进行标记,标记每个字符对应的频率。
2. 计算最优的树的带权路径长度(WPL),也就是最小的带权路径长度。这里主要利用构造哈夫曼树的方法,每次从优先队列中取出两个最小的数,进行加权,再将计算结果放到优先队列中。直到队列中只剩一个元素时,循环结束,计算最优带权长度成功。
3. 最后就进行判断,每组数据符不符合条件了。条件1 判断每组的带权路径长度是否和最优路径长度相等; 条件2 判读每个字符的编码方式是否合法,即每个字符之间的编码是否有歧义,比如A:0000,B:00就有歧义,当遇到0000时不知道表示的是A,还是BB。我使用的方法是使用substr函数进行判断,即如果一个短的字符串是另一个长的字符串的前缀,则就不合法,进行标记。
(ps:建议不熟悉哈夫曼的读者,先去了解哈夫曼树及构造算法,该题自然也就变得简单了)
具体AC代码如下:

#include<bits/stdc++.h>
using namespace std;

int main(){
	int n,x,m,sum=0;
	char c;
	cin>>n;
	getchar();
	map<char,int> mp; //用于标记字符,方便处理 
	priority_queue<int,vector<int>,greater<int> > q;  //按照从小到大排序 
	for(int i=0; i<n; i++){
		cin>>c>>x;
		mp[c]=x;//标记字符对应的编号,对字符进行编号 
		q.push(x);
	}
	while(q.size()!=1){   //计算树的最小带权路径 
		int a=q.top();
		q.pop();
		int b=q.top();
		q.pop();
		sum=sum+(a+b);
		q.push(a+b);
	}
	cin>>m;
	while(m--){
		int sum2=0,flag=0;
		string s[100];
		for(int i=0; i<n; i++){
			cin>>c>>s[i];
			for(int j=0; j<i; j++){
				int d=min(s[i].size(), s[j].size());
				if(s[i].substr(0,d)==s[j].substr(0,d)) flag=1;//检测一个字符串是不是另一个字符串的前缀 
			}
			sum2+=mp[c]*s[i].size();
		}
		if(!flag&&sum==sum2) cout<<"Yes\n";
		else cout<<"No\n";
	}
	return 0;
}

欢迎大家批评改正!!!

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值