Cod sursa(job #3259442)

Utilizator andrei.arnautuAndi Arnautu andrei.arnautu Data 26 noiembrie 2024 12:21:48
Problema Coduri Huffman Scor 60
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.3 kb
/**
 *  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.
    Node* left_child;
    Node* right_child;
    long long subtree_weight;

    static const long long MAX_WEIGHT = 1e15;
    static const int INNER_NODE_ID = -1;

    Node() {}

    Node(Node* _left_child, Node* _right_child, const long long& _subtree_weight) :
        symbol_id(INNER_NODE_ID),
        left_child(_left_child),
        right_child(_right_child),
        subtree_weight(_subtree_weight) {
    }

    Node(const int& _symbol_id, Node* _left_child, Node* _right_child, const long long& _subtree_weight) :
        symbol_id(_symbol_id),
        left_child(_left_child),
        right_child(_right_child),
        subtree_weight(_subtree_weight) {
    }
};

class HuffmanCoder {
private:
    int num_symbols;
    Node* root;
    std::deque<Node*> symbol_nodes;
    std::deque<Node*> inner_nodes;

    void dfs(Node* node, std::vector<std::pair<int, long long>>& symbol_encodings, int crt_length, long long crt_value) {
        if (node->symbol_id != Node::INNER_NODE_ID) {
            symbol_encodings[node->symbol_id] = std::make_pair(crt_length, crt_value);
            delete node;
        } else {
            dfs(node->left_child, symbol_encodings, crt_length + 1, crt_value * 2);
            dfs(node->right_child, symbol_encodings, crt_length + 1, crt_value * 2 + 1);
        }
    }

public:
    HuffmanCoder(const int& _num_symbols) : num_symbols(_num_symbols), root(nullptr) {}

    void add_symbol(const int symbol_id, const int symbol_weight) {
        Node* symbol_node = new Node(symbol_id, nullptr, nullptr, symbol_weight);
        symbol_nodes.push_back(symbol_node);
    }

    Node* dequeue_min_weight_node() {
        long long min_subtree_weight = Node::MAX_WEIGHT;
        std::deque<Node*>* deque_ptr;

        if (!symbol_nodes.empty()) {
            min_subtree_weight = symbol_nodes.front()->subtree_weight;
            deque_ptr = &symbol_nodes;
        }

        if (!inner_nodes.empty() && inner_nodes.front()->subtree_weight < min_subtree_weight) {
            min_subtree_weight = inner_nodes.front()->subtree_weight;
            deque_ptr = &inner_nodes;
        }

        Node* min_weight_node = deque_ptr->front();
        deque_ptr->pop_front();
        deque_ptr->shrink_to_fit();
        return min_weight_node;
    }

    void build_prefix_code_tree() {
        //  Recursively merge nodes until we only have one left (the root)
        while (symbol_nodes.size() + inner_nodes.size() > 1) {
            Node* left_child = dequeue_min_weight_node();
            Node* right_child = dequeue_min_weight_node();
            Node* inner_node = new Node(left_child, right_child, left_child->subtree_weight + right_child->subtree_weight);
            inner_nodes.push_back(inner_node);

            root = inner_node;
        }

        if (!symbol_nodes.empty()) {
            Node* left_child = symbol_nodes.front();
            root = new Node(left_child, root, left_child->subtree_weight + root->subtree_weight);
        }
    }

    std::vector<std::pair<int, long long>> get_symbol_encodings() {
        std::vector<std::pair<int, long long>> symbol_encodings(num_symbols);
        dfs(root, 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;
}