113 lines
3.5 KiB
C++
113 lines
3.5 KiB
C++
#include <functional>
|
|
#include <iostream>
|
|
#include <optional>
|
|
#include <queue>
|
|
#include <unordered_map>
|
|
#include <utility>
|
|
|
|
class HuffmanTree {
|
|
public:
|
|
struct Node {
|
|
long long weight;
|
|
std::optional<std::string> content;
|
|
Node *left = nullptr, *right = nullptr;
|
|
|
|
bool operator<(const Node& other) const {
|
|
return weight < other.weight;
|
|
}
|
|
};
|
|
|
|
enum class DfsEntries { Pre, In, Post };
|
|
|
|
Node* root = nullptr;
|
|
|
|
explicit HuffmanTree(const std::unordered_map<std::string, long long>& freq_map) {
|
|
std::priority_queue<Node*, std::vector<Node*>,
|
|
std::function<bool(Node*, Node*)>>
|
|
nodes_heap([](Node* a, Node* b) { return a->weight > b->weight; });
|
|
for (const auto& [key, freq] : freq_map) {
|
|
nodes_heap.push(new Node{.weight = freq, .content = key});
|
|
}
|
|
while (nodes_heap.size() > 1) {
|
|
Node* node1 = nodes_heap.top();
|
|
nodes_heap.pop();
|
|
Node* node2 = nodes_heap.top();
|
|
nodes_heap.pop();
|
|
Node* new_node = new Node{.weight = node1->weight + node2->weight, .left = node1, .right = node2};
|
|
nodes_heap.push(new_node);
|
|
}
|
|
root = nodes_heap.top();
|
|
}
|
|
|
|
std::unordered_map<std::string, std::vector<bool>> get_encodings() {
|
|
std::unordered_map<std::string, std::vector<bool>> encodings;
|
|
if (root->left == nullptr && root->right == nullptr) {
|
|
encodings[root->content.value()] = {false};
|
|
} else {
|
|
dfs_with_path([&encodings](Node* node, std::vector<bool> path) {
|
|
if (!node->content.has_value()) { return; }
|
|
encodings[node->content.value()] = std::move(path);
|
|
});
|
|
}
|
|
return encodings;
|
|
}
|
|
|
|
protected:
|
|
void dfs_with_path(const std::function<void(Node*, std::vector<bool>)>& func,
|
|
DfsEntries func_entry = DfsEntries::Pre) {
|
|
std::vector<bool> path;
|
|
dfs_with_path(func, func_entry, path);
|
|
}
|
|
|
|
void dfs_with_path(const std::function<void(Node*, std::vector<bool>)>& func,
|
|
DfsEntries func_entry,
|
|
std::vector<bool>& path,
|
|
Node* node = nullptr) {
|
|
if (node == nullptr) { node = root; }
|
|
if (func_entry == DfsEntries::Pre) { func(node, path); }
|
|
if (node->left != nullptr) {
|
|
path.push_back(false);
|
|
dfs_with_path(func, func_entry, path, node->left);
|
|
path.pop_back();
|
|
}
|
|
if (func_entry == DfsEntries::In) { func(node, path); }
|
|
if (node->right != nullptr) {
|
|
path.push_back(true);
|
|
dfs_with_path(func, func_entry, path, node->right);
|
|
path.pop_back();
|
|
}
|
|
if (func_entry == DfsEntries::Post) { func(node, path); }
|
|
}
|
|
};
|
|
|
|
std::ostream& operator<<(std::ostream& os, const std::vector<bool>& bintree_path) {
|
|
for (const auto bin : bintree_path) {
|
|
os << (bin ? 1 : 0);
|
|
}
|
|
return os;
|
|
}
|
|
|
|
int main() {
|
|
std::ios::sync_with_stdio(false);
|
|
std::cin.tie(nullptr);
|
|
|
|
int n;
|
|
std::cin >> n;
|
|
|
|
std::vector<std::string> keys(n);
|
|
std::unordered_map<std::string, long long> freq_map;
|
|
for (int i = 0; i < n; i++) {
|
|
int freq;
|
|
std::cin >> keys[i] >> freq;
|
|
freq_map[keys[i]] = freq;
|
|
}
|
|
|
|
HuffmanTree huffman_tree(freq_map);
|
|
auto encodings = huffman_tree.get_encodings();
|
|
for (const auto& key : keys) {
|
|
std::cout << key << ' ' << encodings[key] << std::endl;
|
|
}
|
|
|
|
return 0;
|
|
}
|