7-19 修理牧场 (25分)(C语言实现)

7-19 修理牧场 (25分)(C语言实现)

农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要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(≤10
​4
​​ ),表示要将木头锯成N块。第二行给出N个正整数(≤50),表示每段木块的长度。

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

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

输出样例:
49

C语言实现

#include<stdio.h>
#include<stdlib.h>
#define MaxData -10 //定义哨兵
typedef int ElementType;
typedef struct TreeNode *HuffmanTree;
struct TreeNode{
	int Weight;
	HuffmanTree Left;
	HuffmanTree Right;
};
typedef struct HeapStruct *MinHeap;
struct HeapStruct{
	ElementType *Elements;//储存堆元素的数组
	int Size;//堆当前元素个数
	int Capacity;//堆的最大容量
};
MinHeap Creates(int MaxSize);
int Huffman(MinHeap H);
ElementType DeleteMin(MinHeap H);
void Insert(MinHeap H,ElementType item);
int IsEmpty(MinHeap H);
int IsFull(MinHeap H);
int main(){
	int n,tp;
	scanf("%d",&n);
	MinHeap h=Creates(n);
	for(int i=0;i<n;i++){
		scanf("%d",&tp);
		Insert(h,tp);
	}
	int p=Huffman(h);
	printf("%d",p);
	return 0;
}
int Huffman(MinHeap H){
	int i;
	int sum=0;
	HuffmanTree T;
	for(int i = 1; H->Size>1;i++){
		int a=DeleteMin(H);//从最小堆中删除一个结点,作为新T的左子结点
		int b=DeleteMin(H);
		sum+=a+b;
		Insert(H,a+b);
	}
	return sum;
}
//最小堆
ElementType DeleteMin(MinHeap H){
	int Parent,Child;
	ElementType MaxItem,temp;
	if(IsEmpty(H)==0){
		printf("-1-");
		return 0;
	}
	MaxItem = H->Elements[1];//取出结点
	//用最大堆中的一个元素从根结点向上过滤下层节点,调整
	temp = H->Elements[H->Size--];
	//判断有没有左右孩子
	for(Parent = 1;Parent*2 <= H->Size;Parent=Child){
		Child=Parent*2;
		//判断有没有右孩子,并找左右孩子中-小-的
		if((Child!=H->Size) && (H->Elements[Child] > H->Elements[Child+1]))
			Child++;
		if(temp <= H->Elements[Child]) break;
		else H->Elements[Parent] = H->Elements[Child];//将-小-孩子拉上来,并进入下一层,
	}
	H->Elements[Parent] = temp;
	return MaxItem;
}
int IsEmpty(MinHeap H){
	if(H->Size==0) return 0;
	else return 1;
}
//最小堆的插入
void Insert(MinHeap H,ElementType item){
	int i;
	if(IsFull(H)==0){
		printf("-2-");
		return;
	}
	i = ++H->Size;//i指向插入后堆中的最后一个元素,并对size加1
	/*比较父结点,如果放到最-xiao-,就会有哨兵,
	这个哨兵就是最-xiao-的,让他不会在比较了。如果不用哨兵,就要加一个&&i>1*/
	for(;H->Elements[i/2]>item;i/=2){
		H->Elements[i]=H->Elements[i/2];//向下过滤
	}
	H->Elements[i]=item;//插入item
}
int IsFull(MinHeap H){
	if(H->Size==H->Capacity)return 0;
	else return 1;
}
MinHeap Creates(int MaxSize){
	MinHeap H = malloc(sizeof(struct HeapStruct));
	H->Elements=malloc((MaxSize+1)*sizeof(ElementType));//创建数组
	H->Size = 0;
	H->Capacity =MaxSize;
	H->Elements[0]=MaxData;//哨兵
	return H;
}

主要思想

这个题主要是将输入的数据进行升序排序后,每次找前两个最小的数经行相加,得到两数和sum,并从序列中删除这两个数。然后在将这个sum插入升序序列中。然后重复操作直到序列中只剩下一个数。然后将这里所有的sum求和就是答案了。
可以看出这就是利用最小堆构建哈夫曼树,求哈夫曼树所有非叶结点的和了。
用最小堆是因为利用最小堆方便插入sum,和删除数据。其时直接进行排序也是一样的。

我写的这个代码有点冗余,是因为我直接改写了以前写好的哈夫曼树。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值