【uva 10954】Add All(算法效率--Huffman编码+优先队列)

题意:有N个数,每次选2个数合并为1个数,操作的开销就是这个新的数。直到只剩下1个数,问最小总开销。

解法:合并的操作可以转化为二叉树上的操作【建模】,每次选两棵根树合并成一棵新树,新树的根权值等于两棵合并前树的根权值和(也与Huffman编码的建立过程类似,选权值最小的两棵树)。

这样总开销就是除了叶子结点的权值和  =》 每个叶子结点的权值*层数(根节点层数为0)之和  =》 WPL(树的所有叶子节点的带权路径长度之和,即该节点到根节点路径长度与节点上权的乘积之和)。

而Huffman树就是带权路径长度WPL最短的二叉树,又称最优二叉树。这样建树WPL就最短的原因很明显了,由于n个父亲节点的哈夫曼树含有2n-1个节点,没有度为1的节点,那么叶子结点数确定了,每层的结点数也确定了,那么权值大的点肯定深度越小越好,权值小的点肯定相对来说深度越大越好,这样建树的WPL就一定是最小的。

于是我们用优先队列来做每次合并权值最小的2个数的操作。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<iostream>
 6 #include<queue>
 7 using namespace std;
 8 const int N=5010,D=(int)1e5+10;
 9 
10 priority_queue<int,vector<int>,greater<int> > q;//使优先队列从小到大排列;不能>>连起来,中间要有空格
11 int main()
12 {
13     int n,x,y,h,i;
14     while (~scanf("%d",&n))
15     {
16       if (!n) break;
17       while (!q.empty()) q.pop();
18       for (i=1;i<=n;i++) scanf("%d",&x),q.push(x);
19       h=0;
20       for (i=1;i<n;i++)
21       {
22         x=q.top(),q.pop();
23         y=q.top(),q.pop();
24         q.push(x+y), h+=x+y;
25       }
26       printf("%d
",h);
27     }
28     return 0;
29 }
原文地址:https://www.cnblogs.com/konjak/p/6018180.html