题目链接
简要思路:
1.首先,我们需要自己建一棵哈夫曼树,这里我们用到了自己写的最小堆,也可以用STL里的优先队列,从最小堆中每次取出两个权值最小的元素,将它们合并,并插入原堆中,重复该操作直到堆中只剩一个元素,说明建树完成。
2.用read函数遍历求取最小字节,遍历哈夫曼树,读到两边都为nullptr的即是作为叶子节点的字符结点。
3.计算样例中字节总长度和其单字符最长的字节长度,总长度必须等于最小字节,最长字节长度小于编码字符数N,才进入下一步判断。
4.进一步的判断是样例中的哈夫曼树能否建成,若存在两个字符的编码拥有相同前缀,会造成歧义,我建树是从nullptr开始,让每个编码开辟路径,当前为‘0’则向左建,向右反之,如若用当前编码建到尽头发现左右不为nullptr,说明有编码开辟过到后面去了,这个编码是某个编码前缀,返回false。又或者说当前编码开辟到某处发现这里已经存在编码到这里的字符了,说明有字符的编码是当前字符编码的前缀,也返回false.
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int MAX = 64;
int bitsum;//最小字节长度
int Size = 0;//最小堆的size
char name[64][64];//存样例的编码
struct Huffman {
bool exist;
int sum;
Huffman* left, * right;
Huffman() { left = right = nullptr; exist = 0; }
}*head;
int frequency[128];//存字符出现频数
Huffman* MinHeap[64];
void Insert(Huffman* target);//结点插入最小堆
Huffman* Delete();//从最小堆中删除结点
void read(Huffman*head,int depth);//求取哈夫曼树字节长度
bool Create_Huffman_Tree(Huffman*& head,char code[],int pos);//试建哈夫曼树
Huffman* Create();
int main() {
int N,a;
char c;
bool f = true;
Huffman* head;
scanf("%d", &N);
for (int i = 0; i < N; i++) {
Huffman *t=new Huffman;
scanf(" %c%d", &c,&t->sum);
Insert(t);
frequency[c - '0'] = t->sum;
}
int K;
head = Create();
read(head,0);
scanf("%d", &K);
while (K--) {
char count[1000];
int s=0, k = 0,i,maxcount=-1,cnt;
Huffman* H=nullptr;
f = true;
for (i = 0; i < N; i++) {
scanf(" %c%s", &c, count);
cnt= strlen(count);
s += cnt*frequency[c-'0'];
if (cnt > maxcount)
maxcount = cnt;
strcpy(name[k++], count);
}
if (s != bitsum || maxcount > N - 1)
f = false;
else {
for (i = 0; i < k; i++)
if (!Create_Huffman_Tree(H, name[i], 0))
break;
if (i != k)
f = false;
}
if (f)
printf("Yes\n");
else
printf("No\n");
delete[]H;
H = nullptr;
}
}
void Insert(Huffman* target) {
int i;
Size++;
for (i = Size; i != 1 && MinHeap[i / 2]->sum > target->sum; i /= 2)
MinHeap[i] = MinHeap[i / 2];
MinHeap[i] = target;
}
Huffman* Delete() {
Huffman* Min = MinHeap[1];
Huffman* temp = MinHeap[Size--];
int parent, child;
for (parent = 1; parent * 2 <= Size; parent = child) {
child = parent * 2;
if (child != Size && MinHeap[child + 1]->sum < MinHeap[child]->sum)//child!=Size表示右儿子存在,因为左儿子位置已经小于等于Size了
child++;
if (temp->sum > MinHeap[child]->sum)
MinHeap[parent] = MinHeap[child];
else
break;
}
MinHeap[parent] = temp;
return Min;
}
void read(Huffman* head,int depth) {
if (head->left == nullptr && head->right == nullptr) {
bitsum += head->sum * depth;
return;
}
if (head->left)
read(head->left, depth + 1);
if (head->right)
read(head->right, depth + 1);
}
bool Create_Huffman_Tree(Huffman*& head,char code[], int pos) {
bool f1=true, f2=true;
if (head == nullptr)
head = new Huffman;
else if (head->exist)
return false;
if (!code[pos]) {
if (head->exist || head->left != nullptr || head->right != nullptr)
return false;
head->exist = true;
}
else if (code[pos] == '0')
f1=Create_Huffman_Tree(head->left, code,pos+1);
else if (code[pos] == '1')
f2=Create_Huffman_Tree(head->right, code, pos + 1);
return (f1&&f2);
}
Huffman* Create() {
Huffman* link=new Huffman;
while (Size != 1) {
link = new Huffman;
Huffman* t1 = Delete(), * t2 = Delete();
link->left = t1;
link->right = t2;
link->sum = t1->sum + t2->sum;
Insert(link);
}
return link;
}