Pagini recente » Cod sursa (job #313586) | Cod sursa (job #514789) | Cod sursa (job #2471987) | Cod sursa (job #2580272) | Cod sursa (job #3259474)
/**
* Worg
*/
#include <deque>
#include <vector>
#include <fstream>
#include <algorithm>
struct Node {
public:
int symbol_id; // Used if the node corresponds to one of the initial symbols.
int left_child_id;
int right_child_id;
long long subtree_weight;
static const long long MAX_WEIGHT = 1e15;
static const int INNER_NODE_ID = -1;
static const int NULL_ID = -2;
Node() {}
Node(const int& _left_child_id, const int& _right_child_id, const long long& _subtree_weight) :
symbol_id(INNER_NODE_ID),
left_child_id(_left_child_id),
right_child_id(_right_child_id),
subtree_weight(_subtree_weight) {
}
Node(const int& _symbol_id, const int& _left_child_id, const int& _right_child_id, const long long& _subtree_weight) :
symbol_id(_symbol_id),
left_child_id(_left_child_id),
right_child_id(_right_child_id),
subtree_weight(_subtree_weight) {
}
};
class HuffmanCoder {
private:
int num_symbols;
int root_id;
std::vector<Node> nodes;
std::deque<int> symbol_node_ids;
std::deque<int> inner_node_ids;
void dfs(int node_id, std::vector<std::pair<int, long long>>& symbol_encodings, int crt_length, long long crt_value) {
if (nodes[node_id].symbol_id != Node::INNER_NODE_ID) {
symbol_encodings[nodes[node_id].symbol_id] = std::make_pair(crt_length, crt_value);
} else {
dfs(nodes[node_id].left_child_id, symbol_encodings, crt_length + 1, crt_value * 2);
dfs(nodes[node_id].right_child_id, symbol_encodings, crt_length + 1, crt_value * 2 + 1);
}
}
public:
HuffmanCoder(const int& _num_symbols) : num_symbols(_num_symbols), root_id(Node::NULL_ID) {
nodes = std::vector<Node>();
nodes.reserve(num_symbols * 2 + 10);
}
void add_symbol(const int symbol_id, const int symbol_weight) {
Node symbol_node(symbol_id, Node::NULL_ID, Node::NULL_ID, symbol_weight);
nodes.push_back(symbol_node);
symbol_node_ids.push_back((int)nodes.size() - 1);
}
int dequeue_min_weight_node() {
long long min_subtree_weight = Node::MAX_WEIGHT;
std::deque<int>* deque_ptr;
if (!symbol_node_ids.empty()) {
min_subtree_weight = nodes[symbol_node_ids.front()].subtree_weight;
deque_ptr = &symbol_node_ids;
}
if (!inner_node_ids.empty() && nodes[inner_node_ids.front()].subtree_weight < min_subtree_weight) {
min_subtree_weight = nodes[inner_node_ids.front()].subtree_weight;
deque_ptr = &inner_node_ids;
}
int min_weight_node_id = deque_ptr->front();
deque_ptr->pop_front();
return min_weight_node_id;
}
void build_prefix_code_tree() {
// Recursively merge nodes until we only have one left (the root)
while (symbol_node_ids.size() + inner_node_ids.size() > 1) {
int left_child_id = dequeue_min_weight_node();
int right_child_id = dequeue_min_weight_node();
Node inner_node(left_child_id, right_child_id, nodes[left_child_id].subtree_weight + nodes[right_child_id].subtree_weight);
nodes.push_back(inner_node);
inner_node_ids.push_back((int)nodes.size() - 1);
root_id = (int)nodes.size() - 1;
}
if (!symbol_node_ids.empty()) {
int left_child_id = symbol_node_ids.front();
nodes.push_back(Node(left_child_id, root_id, nodes[left_child_id].subtree_weight + nodes[root_id].subtree_weight));
root_id = (int)nodes.size() - 1;
}
}
std::vector<std::pair<int, long long>> get_symbol_encodings() {
std::vector<std::pair<int, long long>> symbol_encodings(num_symbols);
dfs(root_id, symbol_encodings, 0, 0);
return symbol_encodings;
}
};
int main() {
std::ifstream fin("huffman.in");
int num_symbols;
fin >> num_symbols;
HuffmanCoder huffman_coder(num_symbols);
std::vector<int> symbol_weights(num_symbols);
for (int symbol_id = 0; symbol_id < num_symbols; symbol_id++) {
fin >> symbol_weights[symbol_id];
huffman_coder.add_symbol(symbol_id, symbol_weights[symbol_id]);
}
fin.close();
huffman_coder.build_prefix_code_tree();
std::vector<std::pair<int, long long>> symbol_encodings = huffman_coder.get_symbol_encodings();
// Compute the total length of the text
long long text_length = 0;
for (int i = 0; i < num_symbols; i++) {
text_length += symbol_encodings[i].first * symbol_weights[i];
}
std::ofstream fout("huffman.out");
fout << text_length << '\n';
for (const auto& symbol_encoding : symbol_encodings) {
fout << symbol_encoding.first << " " << symbol_encoding.second << '\n';
}
fout.close();
return 0;
}