[问题描述]
n堆果子, 每堆果子数量任意,试设计一种最佳方案,将这n堆果子合并为一堆,使得合并工作量最小。
注:规定合并两堆果子的工作量是这两堆果子的数量之和。
[标准输入]
M,N M表示M组测试数据,N表示每组测试数据数量不超过N个,每堆果子数量不超过10000。随后的M行是测试数据。
[标准输出]
M行数据表示对应果子的合并工作量
[输入样例]:
2 6
7, 5, 2, 4
5,6,2,9,7
[输出样例]:
35
65
主要思想
果子合并问题可转化为哈夫曼树问题。先初始化,之后选取两棵根结点的权值最小的树作为左右子树构造一棵新的二叉树,且置新的二叉树的根结点的权值为左右子树上根结点的权值之和,最后把所有新建二叉树根结点的权值加起来即为所求。
调试分析
1、scanf不能对换行进行识别,所以控制输入时要使用cin.get()。
2、初始化权值的时候要赋给其大数,不然作比较时会使程序出现错误。
代码实现
#include<cstdio>//果子合并
#include<iostream>
using namespace std;
const int INT=100000000;
typedef struct{//定义哈弗曼树
int weight;//权值
int parent,lchild,rchild;
}HTNode,*HuffmanTree;
void Select(HuffmanTree &HT,int n,int &s1,int &s2){
/*在前n个结点中,选择两个双亲不为0且权值
最小的结点,并返回它们的序号*/
int s11=INT+1;
int s22=INT+1;
for(int j=1;j<=n;j++){
if(HT[j].parent==0&&s11>HT[j].weight)
{
s11=HT[j].weight;
s1=j;
}
}
for(int j=1;j<=n;j++){
if(HT[j].parent==0&&s22>HT[j].weight&&s11<HT[j].weight)
{
s22=HT[j].weight;
s2=j;
}
}
}
void CreateHuffmanTree(HuffmanTree &HT,int n){//创建哈弗曼树
if(n<=1)
return;
int m=2*n-1;
int i;
HT=new HTNode[m+1];
i=1;
cin>>HT[i].weight;
while(cin.get()!='\n')//控制输入
{
++i;
cin>>HT[i].weight;
}
int s1=1,s2=1,sum=0,w=i;
for(i=1;i<=(2*w-1);i++){
HT[i].parent=0;//初始化
HT[i].lchild=0;
HT[i].rchild=0;
if(i>w)
HT[i].weight=INT+1;
}
for(i=w+1;i<=(2*w-1);++i){
Select(HT,i-1,s1,s2);
HT[s1].parent=i;//将i赋给权值最小的两个结点的双亲
HT[s2].parent=i;
HT[i].lchild=s1;//将权值最小的两个结点的序号分别赋给第i个结点的左孩子和右孩子
HT[i].rchild=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;
sum+=HT[i].weight;//求出权值之和即为合并工作量
}
printf("%d\n",sum);
}
int main(){
int ss,nn;
scanf("%d%d",&ss,&nn);
for(int i=1;i<=ss;i++){
HuffmanTree HT;
CreateHuffmanTree(HT,nn);
}
return 0;
}