数据结构PTA习题:基础实验4-2.7 修理牧场 (25分)

基础实验4-2.7 修理牧场 (25分)

农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要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

我用的方法是:先用输入数据点构造哈夫曼树,再前序遍历所有非叶子结点,求所有非叶结点的数据之和。
该过程需要构造一个最小堆,最小堆内存的是中间过程产生的二叉树根结点地址,当最小堆内只剩下一个二叉树时,该二叉树就是哈夫曼树。
下面举例说明:
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);
 }
}
发布了21 篇原创文章 · 获赞 2 · 访问量 1626

猜你喜欢

转载自blog.csdn.net/wulila/article/details/105540525