基础实验4-2.7 修理牧场 (25分)
农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要N块木头,每块木头长度为整数Li个长度单位,于是他购买了一条很长的、能锯成N块的木头,即该木头的长度是Li的总和。
但是农夫自己没有锯子,请人锯木的酬金跟这段木头的长度成正比。为简单起见,不妨就设酬金等于所锯木头的长度。例如,要将长度为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
我用的方法是:先用输入数据点构造哈夫曼树,再前序遍历所有非叶子结点,求所有非叶结点的数据之和。
该过程需要构造一个最小堆,最小堆内存的是中间过程产生的二叉树根结点地址,当最小堆内只剩下一个二叉树时,该二叉树就是哈夫曼树。
下面举例说明:
4 5 1 2 1 3 1 1
每个数据变成只有1个根结点的二叉树,逐个插入最小堆,形成:
1 1 1 1 2 4 3 5(从数组下标为1的开始存起)
每次找出序列中最小和次小的两个数,构成二叉树,其根结点是两个数之和,并将形成的二叉树插回最小堆:
将哈夫曼树中的所有非叶结点的值相加18+8+10+4+5+2+2=49
C语言实现:
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node * left;
struct node * right;
};
typedef struct node * Bintree;
struct heap
{
Bintree * d;
int size;
};
typedef struct heap * Heap;
Heap Insert(Heap H, Bintree B);//向最小堆内插入元素
Bintree Delete(Heap H);//删除最小堆内最小的元素
Bintree Create(Heap H);//创建哈夫曼树的函数
void Sum(Bintree B);//求最少花费的函数
int sum = 0;//记录结果
int main()
{
int n;
scanf("%d", &n);
int i;
Bintree B;
Heap H;
H = (Heap)malloc(sizeof(struct heap));
H->d = (Bintree *)malloc((n+1) * sizeof(Bintree));
for (i = 0; i <= n; i++)
{
H->d[i] = (Bintree)malloc(sizeof(struct node));
}
H->d[0]->data = -100;//岗哨
H->d[0]->left = H->d[0]->right = NULL;
H->size = 0;
for (i = 1; i <= n; i++)
{
B = (Bintree)malloc(sizeof(struct node));
scanf("%d", &B->data);
B->left = B->right = NULL;
H = Insert(H, B);
}
Bintree HF;
HF = Create(H);
Sum(HF);
printf("%d", sum);
return 0;
}
//向最小堆内插入元素
Heap Insert(Heap H, Bintree B)
{
int i = ++H->size;
while (B->data < H->d[i / 2]->data)
{
H->d[i] = H->d[i / 2];
i = i / 2;
}
H->d[i] = B;
return H;
}
//删除最小堆内最小的元素
Bintree Delete(Heap H)
{
Bintree B;
B = H->d[1];
int i = H->size;
int j = 2;
while (j<i)
{
if (H->d[j]->data > H->d[j + 1]->data)
{
j = j + 1;
}
if (H->d[j]->data < H->d[i]->data)
{
H->d[j / 2] = H->d[j];
}
else { break; }
j = 2 * j;
}
H->d[j/2] = H->d[i];
H->size--;
return B;
}
//创建哈夫曼树的函数
Bintree Create(Heap H)
{
Bintree p1, p2,p;
while (H->size != 1)//直至最小堆内仅剩一个元素,该元素内存的是哈夫曼树的根结点地址
{
p = (Bintree)malloc(sizeof(struct node));
p1 = Delete(H);
p2 = Delete(H);
p->data = p1->data + p2->data;
p->left = p1;
p->right = p2;
H = Insert(H, p);
}
return H->d[H->size];
}
//求最少花费的函数
//前序遍历,将所有非叶结点的data值求和,即为所求值
void Sum(Bintree B)
{
if (B != NULL)
{
if (B->left != NULL && B->right != NULL) { sum = sum + B->data; }
Sum(B->left);
Sum(B->right);
}
}