题目
Description
有n(n<=26)个带权结点,从a开始的n个字母分别表示这n个结点,他们分别代n个权值,试以它们为叶子结点构造一棵哈夫曼树(请按照左子树根节点的权小于等于右子树根节点的权的次序构造,若两结点相等时,按照字典顺序分别为左子树和右子树)。 最后求出该哈夫曼树的带权路径长度.
Input
第一行为一个n的值;第二行为n个字母,中间用空格分开;第三行为n个数字,分别表示着n个字母代表的数值.
Output
共计n+1行,前n行分别为按照字母表的顺序输出各个字母和编码,中间用冒号分开,第n+1行为该哈夫曼树的带权路径长度
Sample Input
7
a b c d e f g
3 7 8 2 5 8 4
Sample Output
a:1101
b:111
c:00
d:1100
e:101
f:01
g:100
100
解题思路
套哈夫曼树模板,在最后遍历的时候把带权路径长度算出来就好了
Code
#include <iostream>
#include <cstdio>
#include <string>
#include <map>
using namespace std;
struct DT{
int data, l, r, addr;
string c;
}a[200], f[200];
int n, num;
map<string, string>ans;
bool bj(string a, string b) {
if(a.size() > b.size()) return 1;
if(a.size() < b.size()) return 0;
return (a > b);
}
void selectsort(int x) {
for(int i = 1; i < x; i ++)
for(int j = i + 1; j <= x; j ++)
if(a[i].data > a[j].data || (a[i].data == a[j].data && bj(a[i].c, a[j].c)))
swap(a[i], a[j]);
}
void print(int x, string s, int d) {
if(f[x].addr == -1) {
ans[f[x].c] = s, num += d * f[x].data;
return;
}
print(f[x].l, s + '0', d + 1), print(f[x].r, s + '1', d + 1);
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i ++) {
char c; c = getchar();
while(!(c >= 'a' && c <= 'z')) c = getchar();
a[i].c = c;
f[i].c = a[i].c;
}
for(int i = 1; i <= n; i ++) {
char c; c = getchar();
while(!(c >= '0' && c <= '9')) c = getchar();
while(c >= '0' && c <= '9') {
a[i].data = a[i].data * 10 + (c - '0');
c = getchar();
}
f[i].data = a[i].data, a[i].addr = i, f[i].addr = -1;
}
int t = n + 1;
for(int i = n; i > 1; i --, t ++) {
selectsort(i);
f[t] = (DT){ a[1].data + a[2].data, a[1].addr, a[2].addr, 0, a[1].c + a[2].c};
a[1].data = f[t].data, a[1].addr = t, a[1].c = f[t].c;
a[2].data = a[i].data, a[2].addr = a[i].addr, a[2].c = a[i].c;
}
print(t - 1, "", 0);
for(int i = 0; i < 26; i ++) {
map<string, string>::iterator it;
string ls = ""; char c = i + 'a';
ls = ls + c;
it = ans.find(ls);
if(it != ans.end())
cout << it -> first << ":" << it -> second << endl;
}
printf("%d", num);
}