修理牧场【哈夫曼算法】

题目描述
农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要N块木头,每块木头长度为整数L​i个长度单位,于是他购买了一条很长的、能锯成N块的木头,即该木头的长度是L​i 的总和。

但是农夫自己没有锯子,请人锯木的酬金跟这段木头的长度成正比。为简单起见,不妨就设酬金等于所锯木头的长度。例如,要将长度为20的木头锯成长度为8、7和5的三段,第一次锯木头花费20,将木头锯成12和8;第二次锯木头花费12,将长度为12的木头锯成7和5,总花费为32。如果第一次将木头锯成15和5,则第二次锯木头花费15,总花费为35(大于32)。

请编写程序帮助农夫计算将木头锯成N块的最少花费。

输入格式:
输入首先给出正整数N(≤104
​​ ),表示要将木头锯成N块。第二行给出N个正整数(≤50),表示每段木块的长度。

输出格式:
输出一个整数,即将木头锯成N块的最少花费。

输入样例:
8
4 5 1 2 1 3 1 1

输出样例:
49

样例示意图:
在这里插入图片描述
题目思路:
哈夫曼算法的考察。

参考代码:

#include <stdio.h>
#include <stdlib.h>//malloc()函数头文件。

int n;
int a[10001];//n≤10^4。a数组存储输入的每段木块长度。

/*哈夫曼树结点的结构*/
typedef struct HTNode{
    
    
	int data;//哈夫曼树中结点的权值。
	struct HTNode* left;
	struct HTNode* right;
}HTNode,*ht;

/*哈夫曼树的创建*/
ht createHT()
{
    
    
	ht ptrArr[n];//用来保存输入数据的ht类型的指针数组。
	ht ptr,pRoot=NULL;//定义两个ht类型的指针变量。
	int i,j;
	
	/*初始化结构体指针数组,数组中每一个元素为一个结构体指针类型。*/
	for(i=0;i<n;i++)
	{
    
    
		ptr=(ht)malloc(sizeof(HTNode));
		ptr->data=a[i];
		ptr->left=ptr->right=NULL;
		ptrArr[i]=ptr;
	}
	
	for(i=1;i<n;i++)
	{
    
    
	    //进行n-1次循环建立哈夫曼树。
        //k1表示森林中具有最小权值的树根结点的下标,k2为次最小的下标。
		int k1=-1,k2;
		//先取结构体指针数组的前两个数组下标,充当标志,便于别下来比较找出最小权值的树根节点下标及次最小的下标。
		for(j=0;j<n;j++)
		{
    
    
			if(ptrArr[j]!=NULL&&k1==-1)
			{
    
    
				k1=j;
				continue;
			}
			if(ptrArr[j]!=NULL)
			{
    
    
				k2=j;
				break;
			}
		}
		
		/*比较,找出最小权值的树根节点下标及次最小的下标。*/
		for(j=k2;j<n;j++)
		{
    
    
			if(ptrArr[j]!=NULL)
			{
    
    
				if(ptrArr[j]->data<ptrArr[k1]->data)
				{
    
    
					k2=k1;
					k1=j;
				}
				else if(ptrArr[j]->data<ptrArr[k2]->data)
				  k2=j;
			}
		}
	  
	  //由最小权值树和次最小权值树建立一棵新树,pRoot指向树根结点。
	  pRoot=(ht)malloc(sizeof(HTNode));
	  pRoot->data=ptrArr[k1]->data+ptrArr[k2]->data;
	  pRoot->left=ptrArr[k1];
      pRoot->right=ptrArr[k2];
	
	  /*删除两小添新人*/
	  ptrArr[k1]=pRoot;//将指向新树的指针赋给ptrArr指针数组中k1位置。
	  ptrArr[k2]=NULL;//k2位置为空。
	}
	
	return pRoot;
}

int calculate(ht T,int len)
{
    
    
	if(T==NULL)
	 return 0;//空树返回0。
	else
	{
    
    
		if(T->left==NULL&&T->right==NULL)//访问到叶子节点。
		 return T->data*len;
		else
		 return calculate(T->left,len+1)+calculate(T->right,len+1);//向下递归计算。
	}
}

int main()
{
    
    
	scanf("%d",&n);
	
	int i;
	for(i=0;i<n;i++)
	 scanf("%d",&a[i]);
	
	ht T=createHT();
	printf("%d",calculate(T,0));
	
	return 0;
}

参考资料传送门:
https://blog.csdn.net/baobeiduoduo/article/details/90412356?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control&dist_request_id=0258dd52-ff36-4bb8-8a3d-40b581451d02&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control

猜你喜欢

转载自blog.csdn.net/qq_46139801/article/details/114207101