首页 > 代码库 > 【uva 10954】Add All(算法效率+Huffman编码+优先队列)

【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\n",h);27     }28     return 0;29 }

 

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