题目链接:https://vjudge.net/problem/UVA-12676
题目大意
一串文本中包含 N 个不同字母,经过哈夫曼编码后,得到这 N 个字母的相应编码长度,求文本的最短可能长度。
分析
哈夫曼树有这样一个性质,对于位于第 i 层的节点 A 和 第 i + 1 层的节点 B,A 出现的频率肯定大于等于 B,不然就可以把这两个节点互换,可以得到更优的哈夫曼树,因此,A 所能取到的最小频率,就是 i + 1 层所有节点出现频率的最大值,而根据题意,哈夫曼树的最底层节点频率可以全部设置为 1,如此可以一层层往上递推。
代码如下
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define INIT() ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 5 #define Rep(i,n) for (int i = 0; i < (n); ++i) 6 #define For(i,s,t) for (int i = (s); i <= (t); ++i) 7 #define rFor(i,t,s) for (int i = (t); i >= (s); --i) 8 #define ForLL(i, s, t) for (LL i = LL(s); i <= LL(t); ++i) 9 #define rForLL(i, t, s) for (LL i = LL(t); i >= LL(s); --i) 10 #define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i) 11 #define rforeach(i,c) for (__typeof(c.rbegin()) i = c.rbegin(); i != c.rend(); ++i) 12 13 #define pr(x) cout << #x << " = " << x << " " 14 #define prln(x) cout << #x << " = " << x << endl 15 16 #define LOWBIT(x) ((x)&(-x)) 17 18 #define ALL(x) x.begin(),x.end() 19 #define INS(x) inserter(x,x.begin()) 20 21 #define ms0(a) memset(a,0,sizeof(a)) 22 #define msI(a) memset(a,inf,sizeof(a)) 23 #define msM(a) memset(a,-1,sizeof(a)) 24 25 #define MP make_pair 26 #define PB push_back 27 #define ft first 28 #define sd second 29 30 template<typename T1, typename T2> 31 istream &operator>>(istream &in, pair<T1, T2> &p) { 32 in >> p.first >> p.second; 33 return in; 34 } 35 36 template<typename T> 37 istream &operator>>(istream &in, vector<T> &v) { 38 for (auto &x: v) 39 in >> x; 40 return in; 41 } 42 43 template<typename T1, typename T2> 44 ostream &operator<<(ostream &out, const std::pair<T1, T2> &p) { 45 out << "[" << p.first << ", " << p.second << "]" << " "; 46 return out; 47 } 48 49 inline int gc(){ 50 static const int BUF = 1e7; 51 static char buf[BUF], *bg = buf + BUF, *ed = bg; 52 53 if(bg == ed) fread(bg = buf, 1, BUF, stdin); 54 return *bg++; 55 } 56 57 inline int ri(){ 58 int x = 0, f = 1, c = gc(); 59 for(; c<48||c>57; f = c=='-'?-1:f, c=gc()); 60 for(; c>47&&c<58; x = x*10 + c - 48, c=gc()); 61 return x*f; 62 } 63 64 typedef long long LL; 65 typedef unsigned long long uLL; 66 typedef pair< double, double > PDD; 67 typedef pair< int, int > PII; 68 typedef pair< int, PII > PIPII; 69 typedef pair< string, int > PSI; 70 typedef pair< int, PSI > PIPSI; 71 typedef set< int > SI; 72 typedef vector< int > VI; 73 typedef vector< VI > VVI; 74 typedef vector< PII > VPII; 75 typedef map< int, int > MII; 76 typedef map< int, PII > MIPII; 77 typedef map< string, int > MSI; 78 typedef multimap< int, int > MMII; 79 //typedef unordered_map< int, int > uMII; 80 typedef pair< LL, LL > PLL; 81 typedef vector< LL > VL; 82 typedef vector< VL > VVL; 83 typedef priority_queue< int > PQIMax; 84 typedef priority_queue< int, VI, greater< int > > PQIMin; 85 const double EPS = 1e-10; 86 const LL inf = 0x7fffffff; 87 const LL infLL = 0x7fffffffffffffffLL; 88 const LL mod = 1e9 + 7; 89 const int maxN = 1e4 + 7; 90 const LL ONE = 1; 91 const LL evenBits = 0xaaaaaaaaaaaaaaaa; 92 const LL oddBits = 0x5555555555555555; 93 94 struct Node{ 95 LL weight = 0, len; 96 97 bool operator< (const Node &x) const { 98 if(len == x.len) return weight > x.weight; 99 return len < x.len; 100 } 101 }; 102 103 int N; 104 105 int main(){ 106 //freopen("MyOutput.txt","w",stdout); 107 //freopen("input.txt","r",stdin); 108 INIT(); 109 while(cin >> N) { 110 priority_queue< Node > maxH; 111 Rep(i, N) { 112 Node t; 113 cin >> t.len; 114 maxH.push(t); 115 } 116 117 // nowLen: 记录当前处理第几层 118 // nowMax: 记录 i + 1 层的最大值 119 // tmpMax: 记录当前层 i 层的最大值 120 LL nowLen = maxH.top().len, nowMax = 1, tmpMax = -1; 121 while(maxH.size() > 1) { 122 Node a = maxH.top(); maxH.pop(); 123 Node b = maxH.top(); maxH.pop(); 124 125 if(a.len == nowLen) { 126 // 代码看到这里也许会有疑问,就是如果 a.weight == 0 或是 b.weight == 0,难道不要把节点扔回去重新取吗? 127 // 其实不需要,因为它们就是最小的 128 // 设max(i)表示倒数第 i 层的频率最大值,min(i)表示倒数第 i 层的频率最小值 129 // 容易看出 max(i) <= 2^i, min(i) >= 2^{i-1} 130 // 于是倒数第 i + 1 层权值为 0 的节点会被赋值为 max(i) 131 // 而那些权值不为 0 的节点,权值必然大于等于2倍的min(i),为 2^i,大于等于 max(i) 132 if(a.weight == 0) a.weight = nowMax; 133 if(b.weight == 0) b.weight = nowMax; 134 tmpMax = max(tmpMax, b.weight); 135 136 a.weight += b.weight; 137 --a.len; 138 maxH.push(a); 139 } 140 else { 141 nowLen = a.len; 142 nowMax = tmpMax; 143 tmpMax = -1; 144 maxH.push(a); 145 maxH.push(b); 146 } 147 } 148 cout << maxH.top().weight << endl; 149 } 150 return 0; 151 }