哈夫曼算法 POJ 3253
Fence Repair
Time Limit: 2000MS
Memory Limit: 65536K
Total Submissions: 6301
Accepted: 1947
Description
Farmer John wants to repair a small length of the fence around the pasture. He measures the fence and finds that he needs N (1 ≤ N ≤ 20,000) planks of wood, each having some integer length Li (1 ≤ Li ≤ 50,000) units. He then purchases a single long board just long enough to saw into the N planks (i.e., whose length is the sum of the lengths Li). FJ is ignoring the "kerf", the extra length lost to sawdust when a sawcut is made; you should ignore it, too.
FJ sadly realizes that he doesn't own a saw with which to cut the wood, so he mosies over to Farmer Don's Farm with this long board and politely asks if he may borrow a saw.
Farmer Don, a closet capitalist, doesn't lend FJ a saw but instead offers to charge Farmer John for each of the N-1 cuts in the plank. The charge to cut a piece of wood is exactly equal to its length. Cutting a plank of length 21 costs 21 cents.
Farmer Don then lets Farmer John decide the order and locations to cut the plank. Help Farmer John determine the minimum amount of money he can spend to create the N planks. FJ knows that he can cut the board in various different orders which will result in different charges since the resulting intermediate planks are of different lengths.
Input
Line 1: One integer N, the number of planks
Lines 2..N+1: Each line contains a single integer describing the length of a needed plank
Output
Line 1: One integer: the minimum amount of money he must spend to make N-1 cuts
Sample Input
3
8
5
8
Sample Output
34
Hint
He wants to cut a board of length 21 into pieces of lengths 8, 5, and 8.
The original board measures 8+5+8=21. The first cut will cost 21, and should be used to cut the board into pieces measuring 13 and 8. The second cut will cost 13, and should be used to cut the 13 into 8 and 5. This would cost 21+13=34. If the 21 was cut into 16 and 5 instead, the second cut would cost 16 for a total of 37 (which is more than 34).
对于长度 L为木条要其砍为规定数目为N并且每根木条的长度为L(i)的木条 , 每次把一根木条砍为两截时所花的成本与原始木条的常度相等,即:如果原始木条长度为5的话,把其砍为3和2的两截所花费的成本就为5,
题目的要求为 对于原始长度为L的木条,把其分为规定N根长度有规定的木条时,所花的最低成本应该为多少。
对于题目的解决方法其实就是采用哈夫曼的思想, 所谓的哈夫曼树其实就是所有叶子节点到根节点的路径长度和最小的二叉树。
每个节点的路径长度指的是该节点到根节点所经过的路径数
对于有n个叶子节点的哈夫曼树,其节点的总数为2n-1个节点。
把题目对应到得二叉树的话就是规定的木条数就是哈夫曼树的叶子节点,每个叶子节点的权值就是该每根木条的实际长度,对于要求所花的成本最低,其实就是利用所给的叶子节点构造哈夫曼树,然后求相应节点的权值的和。就是最后最低的成本。
算法描述
1 把所给的木条的长度进行排序,把花费成本consum初始化为0
2 每次取最小的两个节点进行结合(即权值相加,也就是长度相加)构成新的节点,在原始数组中删除,consum加上新节点的权值。
3 把新的节点按插入排序的方式插入已排序的节点数组,
4 判断排序数组长度是否小于等于1,如是的话转到5,如果否的话转到2
5 consum为最后所花费的最低成本
所遇到的问题:
第1不采用快速排序的方式
在第3步如果对于插入新原始后的数组采用快速排序的话,导致最后的程序提交时超时
AC的程序
#include<iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
bool compare(const int &a,const int &b)
{
if(a<b)return true;else return false;
}
int main(void)
{
unsigned int n,temp;
unsigned int i,j;
unsigned long a,b,consum;
unsigned int count;
vector<unsigned int> vect;
cin>>n;
for(i=0;i<n;i++)
{
cin>>temp;
vect.push_back(temp);
}
consum=0;
sort(vect.begin(),vect.end(),compare); //第一遍快速排序
vector<unsigned int> ::iterator it,pre;
for(i=0;i<vect.size();i+=2)
{
if(i==vect.size()-1)
{
temp=vect[i];
}else{
temp=vect[i]+vect[i+1]; //取权值最低的两个数组元素构成新的节点
consum+=temp; //花费成本累计新节点的权值
}
for(j=i+2;j<vect.size();j++) //按插入排序的方式插入新的数组元素
{
it=vect.begin()+j;
if(temp<*it)
{
vect.insert(it,temp);
break;
}
}
if(j>=vect.size())
{
vect.push_back(temp);
}
}
cout<<consum<<endl; //打印最后所花费的最低成本
return 0;
}