来源:
http://ac.jobdu.com/problem.php?pid=1172
题目描述:
哈夫曼树,第一行输入一个数n,表示叶结点的个数。需要用这些叶结点生成哈夫曼树,根据哈夫曼树的概念,这些结点有权值,即weight,题目需要输出所有结点的值与权值的乘积之和。
输入:
输入有多组数据。
每组第一行输入一个数n,接着输入n个叶节点(叶节点权值不超过100,2<=n<=1000)。
输出:
输出权值。
样例输入:
5
1 2 2 5 9
样例输出:
37
方法一:构建Haffman Tree, 然后计算叶节点的权值。
<pre name="code" class="cpp">#include <stdio.h>
#include <algorithm>
using namespace std;
struct Node
{
int e;
Node *lchild, *rchild;
};
bool cmp(Node *a, Node *b)
{
return a->e < b->e;
}
Node *arr[100];
int CreateHaffmanTree(int n)
{
int i=0;
while(i<n-1)
{
Node *root = (Node*)malloc(sizeof(Node));
root->lchild = arr[i];
root->rchild = arr[i+1];
root->e = arr[i]->e + arr[i+1]->e;
arr[++i] = root;
sort(arr+i,arr+n,cmp);
}
return 0;
}
int countHaffmanTree(Node *root, int level)
{
if(root->lchild || root->rchild)
{
return countHaffmanTree(root->lchild, level+1)+
countHaffmanTree(root->rchild, level+1);
}
else return root->e * level;
}
int main()
{
freopen("in.txt", "r", stdin);
int n,e;
scanf("%d",&n);
for(int i=0; i<n; i++)
{
scanf("%d",&e);
Node *root = (Node*)malloc(sizeof(Node));
root->e = e;
root->lchild = NULL;
root->rchild = NULL;
arr[i] = root;
}
sort(arr, arr+n, cmp);
CreateHaffmanTree(n);
printf("%d\n",countHaffmanTree(arr[n-1], 0));
return 0;
}
方法二:不建树,每次吧排序后最小的两个值加入权值和,将还未统计过的值和新产生的值(最小的两个数的和)重新排序。
<pre name="code" class="cpp">#include <stdio.h>
#include <algorithm>
using namespace std;
int main()
{
freopen("in.txt","r",stdin);
int n, sum = 0;
int arr[100];
scanf("%d",&n);
for(int i=0; i<n; i++)
{
scanf("%d",&arr[i]);
}
sort(arr,arr+n);
i = 0;
while(i<n-1)
{
sum+= arr[i]+arr[i+1];
arr[i+1] = arr[i]+arr[i+1];
i++;
sort(arr+i,arr+n);
}
for(i=0; i<n; i++)
printf("%d ",arr[i]);
printf("%d ",sum);
return 0;
}