zoukankan      html  css  js  c++  java
  • P2168 荷马史诗

    P2168 荷马史诗

    此题好像是Huffman树经典例题,不用哈夫曼树都对不起哈夫曼(bushi

    0x00 Huffman树

    1. 定义:带权路径长度WPL最短的多叉树(最优多叉树)构造这种树的算法最早是由哈夫曼(Huffman)1952年提出,这种树在信息检索中很有用。

    2. 构树过程:每次取出根节点中权值最小的k个根节点进行合并,新的根节点权值为k个原根节点的权值之和

    3. 树的路径长度PL:从树根到树的每个节点的路径长度之和(节点数相同时,完全二叉树为这种路径长度最短的二叉树)。

    4. 树的带权路径长度WPL:树的所有叶子节点的带权路径长度(该节点到根节点路径长度与节点上权的乘积)之和。

    5. 哈弗曼编码: n个节点的哈夫曼树含有2n-1个节点,没有度为1的节点 编码从叶子节点到根节点,译码从根节点到叶子节点。

      从哈夫曼树根节点开始,对左子树分配码“0”,右子树分配码“1”,一直到达叶子节点为止,然后将从树根沿每条路径到达叶子结点的代码排列起来,便得到了哈夫曼编码。

    0x01 构建模型

    什么时候用huffman树?

    考虑它的性质:带权路径长度最小~

    也就是(点的权值 imes点到根节点的距离)最小

    我们需要找四个东西:最值;权值;距离;叉数

    在这个题里,最值就是编码的最短长度,权值就是单词出现次数,距离就是字符串(s_i)的长度,叉数就是几进制。

    我们可以先根据单词出现次数构造Huffman树,然后利用它的性质求解

    0x02 具体实现

    因为在构树的时候,要找最小值,所以我们选用小根堆(优先队列)来存点的权值(莫名像合并果子(好吧就是

    补节点:k叉Huffman树在最后合并时会出现根节点数小于k的情况,显然这不是最优解,所以我们要在构树之前用权值为0的点补上空位,使得

    [(总点数-1)\%(k-1)==0 ]

    用pair叭别用结构体了

    pair存当前点的权值和层数

    0x03 代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<long long,long long> PLL;
    typedef long long ll;
    const int N=10001;
    
    ll n,k,cnt,ans=0;
    priority_queue<PLL,vector<PLL>,greater<PLL> > q;
    
    int main(){
    	cin>>n>>k;
    	for(int i=1;i<=n;i++){
    		ll a;
    		cin>>a;
    		q.push({a,1});
    	}
    	while((q.size()-1)%(k-1)!=0) q.push({0,1});//补点 
    	while(q.size()>=k){
    		ll h=-1,w=0;
    		for(int i=1;i<=k;i++){
    			PLL t=q.top();
    			q.pop();
    			h=max(h,t.second);
    			w+=t.first;
    		}
    		ans+=w;
    		q.push({w,h+1});
    	}
    	PLL res=q.top();
    	printf("%lld
    %lld
    ",ans,res.second-1);
    	
    	return 0;
    }
    
    

    好!

  • 相关阅读:
    Node.js 0.12: 正确发送HTTP POST请求
    pm2 常用命令
    IntelliJ IDEA Configuring projects
    socket.io入门整理教程
    幂等函数
    Linux 下 ps 命令
    Linux 下 tail 命令
    Linux下chmod命令
    Linux下ll命令与ls -l
    Thrift——初学
  • 原文地址:https://www.cnblogs.com/wsyunine/p/14380081.html
Copyright © 2011-2022 走看看