九度oj地址:http://ac.jobdu.com/problem.php?pid=1172
哈夫曼树,第一行输入一个数n,表示叶结点的个数。需要用这些叶结点生成哈夫曼树,根据哈夫曼树的概念,这些结点有权值,即weight,题目需要输出所有结点的值与权值的乘积之和。
输入有多组数据。
每组第一行输入一个数n,接着输入n个叶节点(叶节点权值不超过100,2<=n<=1000)。
输出权值。
5 1 2 2 5 9
37
第一种方法:不建树,这种方法要简单一点
#include <stdio.h> #include <string.h> #include <algorithm> #include<iostream> #include<stack> using namespace std; int result[1001]; //哈夫曼树的权值就是除了所有叶子 //的节点的权值的和 int main(){ int n,i,sum,num; while(scanf("%d",&n)!=EOF){ memset(result,0,n); for(i=0;i<n;i++) scanf("%d",&result[i]); //进行排序,从小到大 sort(result,result+n); i=1; sum=0; while(i<n){ //每次都要进行重新排序,因为生成了新的节点 sort(result+i-1,result+n); //计算父亲 num = result[i-1]+result[i]; sum+=num; //将新的节点赋值 result[i]=num; i++; } printf("%d\n",sum); } return 0; }
第二种方法:建树
<pre name="code" class="cpp">#include <stdio.h> #include <string.h> #include <algorithm> #include<iostream> #include<stack> #define maxvalue 0x7fffffff//这个是int的最大值 using namespace std; //创建节点的结构体 struct huffman{ int weight; int parent,lchild,rchild; }list[5000]; int main() { int n,m; int i,j; int ans; int x1,x2;//用来存放树生成过程中的最小和次小的角标 int m1,m2;//用来存放树生成过程中的最小和次小的值 while(scanf("%d",&n)!=EOF) { m=2*n-1; for(i=0;i<m;i++) list[i].parent=list[i].lchild=list[i].rchild=-1; for(i=0;i<n;i++) scanf("%d",&list[i].weight); ans=0; for(i=0;i<n-1;i++){ x1=x2=0; m1=m2=maxvalue; for(j=0;j<n+i;j++){ //用来判断新的节点是否小于最小且没有双亲 //如果小于最小的话就把当前的数和角标给x1和m1 //并且在x1和m1中存入当前最小的角标和值 if(list[j].weight<m1&&list[j].parent==-1){ x2=x1; m2=m1; x1=j; m1=list[j].weight; } //用来判断是不是小于次小,如果小于的话就替换次小 else if(list[j].weight<m2&&list[j].parent==-1){ x2=j; m2=list[j].weight; } } list[x1].parent=n+i; list[x2].parent=n+i; list[n+i].lchild=x1; list[n+i].rchild=x2; list[n+i].weight=list[x1].weight+list[x2].weight; ans+=list[n+i].weight; } printf("%d\n",ans); } return 0; }