【SSL 1408】【哈夫曼树】哈夫曼树(二)(带权值路径)

【树】哈夫曼树二

SSL 1408 【树】哈夫曼树(二)
1407【树】哈夫曼树(一) 题解
1409【树】哈夫曼树(三) 题解


题目

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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值