UVA 12676 Inverting Huffman
阅读原文时间:2023年07月10日阅读:1

题目链接:https://vjudge.net/problem/UVA-12676

题目大意

  一串文本中包含 N 个不同字母,经过哈夫曼编码后,得到这 N 个字母的相应编码长度,求文本的最短可能长度。

分析

  哈夫曼树有这样一个性质,对于位于第 i 层的节点 A 和 第 i + 1 层的节点 B,A 出现的频率肯定大于等于 B,不然就可以把这两个节点互换,可以得到更优的哈夫曼树,因此,A 所能取到的最小频率,就是 i + 1 层所有节点出现频率的最大值,而根据题意,哈夫曼树的最底层节点频率可以全部设置为 1,如此可以一层层往上递推。

代码如下

#include
using namespace std;

#define INIT() ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define Rep(i,n) for (int i = 0; i < (n); ++i) #define For(i,s,t) for (int i = (s); i <= (t); ++i) #define rFor(i,t,s) for (int i = (t); i >= (s); --i)
#define ForLL(i, s, t) for (LL i = LL(s); i <= LL(t); ++i) #define rForLL(i, t, s) for (LL i = LL(t); i >= LL(s); --i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)
#define rforeach(i,c) for (__typeof(c.rbegin()) i = c.rbegin(); i != c.rend(); ++i)

#define pr(x) cout << #x << " = " << x << " "
#define prln(x) cout << #x << " = " << x << endl

#define LOWBIT(x) ((x)&(-x))

#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())

#define ms0(a) memset(a,0,sizeof(a))
#define msI(a) memset(a,inf,sizeof(a))
#define msM(a) memset(a,-1,sizeof(a))

#define MP make_pair
#define PB push_back
#define ft first
#define sd second

template
istream &operator>>(istream &in, pair &p) {
in >> p.first >> p.second;
return in;
}

template
istream &operator>>(istream &in, vector &v) {
for (auto &x: v)
in >> x;
return in;
}

template
ostream &operator<<(ostream &out, const std::pair &p) {
out << "[" << p.first << ", " << p.second << "]" << "\n";
return out;
}

inline int gc(){
static const int BUF = 1e7;
static char buf[BUF], *bg = buf + BUF, *ed = bg;

 if(bg == ed) fread(bg = buf, , BUF, stdin);  
 return \*bg++;  

}

inline int ri(){
int x = , f = , c = gc();
for(; c<||c>; f = c=='-'?-:f, c=gc());
for(; c>&&c<; x = x* + c - , c=gc());
return x*f;
}

typedef long long LL;
typedef unsigned long long uLL;
typedef pair< double, double > PDD;
typedef pair< int, int > PII;
typedef pair< int, PII > PIPII;
typedef pair< string, int > PSI;
typedef pair< int, PSI > PIPSI;
typedef set< int > SI;
typedef vector< int > VI;
typedef vector< VI > VVI;
typedef vector< PII > VPII;
typedef map< int, int > MII;
typedef map< int, PII > MIPII;
typedef map< string, int > MSI;
typedef multimap< int, int > MMII;
//typedef unordered_map< int, int > uMII;
typedef pair< LL, LL > PLL;
typedef vector< LL > VL;
typedef vector< VL > VVL;
typedef priority_queue< int > PQIMax;
typedef priority_queue< int, VI, greater< int > > PQIMin;
const double EPS = 1e-;
const LL inf = 0x7fffffff;
const LL infLL = 0x7fffffffffffffffLL;
const LL mod = 1e9 + ;
const int maxN = 1e4 + ;
const LL ONE = ;
const LL evenBits = 0xaaaaaaaaaaaaaaaa;
const LL oddBits = 0x5555555555555555;

struct Node{
LL weight = , len;

 bool operator< (const Node &x) const {  
     if(len == x.len) return weight > x.weight;  
     return len < x.len;  
 }  

};

int N;

int main(){
//freopen("MyOutput.txt","w",stdout);
//freopen("input.txt","r",stdin);
INIT();
while(cin >> N) {
priority_queue< Node > maxH;
Rep(i, N) {
Node t;
cin >> t.len;
maxH.push(t);
}

     // nowLen: 记录当前处理第几层  
     // nowMax: 记录 i + 1 层的最大值  
     // tmpMax: 记录当前层 i 层的最大值  
     LL nowLen = maxH.top().len, nowMax = , tmpMax = -;  
     while(maxH.size() > ) {  
         Node a = maxH.top(); maxH.pop();  
         Node b = maxH.top(); maxH.pop();

         if(a.len == nowLen) {  
             // 代码看到这里也许会有疑问,就是如果 a.weight == 0 或是 b.weight == 0,难道不要把节点扔回去重新取吗?  
             // 其实不需要,因为它们就是最小的  
             // 设max(i)表示倒数第 i 层的频率最大值,min(i)表示倒数第 i 层的频率最小值  
             // 容易看出 max(i) <= 2^i, min(i) >= 2^{i-1}  
             // 于是倒数第 i + 1 层权值为 0 的节点会被赋值为 max(i)  
             // 而那些权值不为 0 的节点,权值必然大于等于2倍的min(i),为 2^i,大于等于 max(i)  
             if(a.weight == ) a.weight = nowMax;  
             if(b.weight == ) b.weight = nowMax;  
             tmpMax = max(tmpMax, b.weight);

             a.weight += b.weight;  
             --a.len;  
             maxH.push(a);  
         }  
         else {  
             nowLen = a.len;  
             nowMax = tmpMax;  
             tmpMax = -;  
             maxH.push(a);  
             maxH.push(b);  
         }  
     }  
     cout << maxH.top().weight << endl;  
 }  
 return ;  

}