农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要N块木头,每块木头长度为整数Li个长度单位,于是他购买了一条很长的、能锯成N块的木头,即该木头的长度是Li的总和。
但是农夫自己没有锯子,请人锯木的酬金跟这段木头的长度成正比。为简单起见,不妨就设酬金等于所锯木头的长度。例如,要将长度为20的木头锯成长度为8、7和5的三段,第一次锯木头花费20,将木头锯成12和8;第二次锯木头花费12,将长度为12的木头锯成7和5,总花费为32。如果第一次将木头锯成15和5,则第二次锯木头花费15,总花费为35(大于32)。
请编写程序帮助农夫计算将木头锯成N块的最少花费。
输入格式:
输入首先给出正整数N(≤10000 ),表示要将木头锯成N块。第二行给出N个正整数(≤50),表示每段木块的长度。
输出格式:
输出一个整数,即将木头锯成N块的最少花费。
输入样例:
8
4 5 1 2 1 3 1 1
输出样例:
49
思路
构造最优二叉树,将除叶节点外所有的节点权值加和。即为所求。
实际上是没必要构造一颗树的,运用他的原理即可
其实这两个解法差不多,但是c++更加的简单易于理解,在时间上也是很短的。c相对而言就比较暴力了。相当于对c++解法的底层解释。注重基础。
c++解法
#include<stdio.h>
#include<queue>
using namespace std;
priority_queue<int,vector<int>,greater<int> > Q;
int main(){
int x,n,sum = 0;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&x);
Q.push(x);
}
while(Q.size()>1){
int a=Q.top();
Q.pop();
int b=Q.top();
Q.pop();
Q.push(a+b);
sum+=a+b;
}
printf("%d",sum);
return 0;
}
在这里解释一下这句话
priority_queue<int,vector<int>,greater<int> > Q;
priority_queue<Type, Container, Functional>,其中Type 为数据类型,Container为保存数据的容器,Functional 为元素比较方式。
Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector。
greater 可以实现由底部到顶部大到小实现。
所以这道题的步骤就是,
push出两个最小值并相加,将相加的值加到sum并放回Q中,然后会重新排列大小。
以此类推
不仅代码量很少,时间也是很短的,考试的时候可以使用,平时练习不建议,有点投机取巧。练习还是用c一步步实现他的每一个步骤。
c解法
用c语言其实就是对c++的具体实现,(可能我这个不是最好的解法。)但是每次取每次放都需要重新排序,这将是一件很累的事情。所以干脆就不排序了,直接放在那,取的时候再去判断最小值。
#include <stdio.h>
int a[10010],n;
#define Max 10000000
int findMin(){
int min = Max+1,i;
for (i = 0; i<n; i++)
if (min>a[i]) min = a[i];
return min;
}
void Delete(int x){
int i;
for (i = 0; i<n; i++)
if (a[i] == x) {
a[i] = Max;
return;
}
}
void add(int x){
int i;
for (i = 0; i<n; i++)
if (a[i] == Max) {
a[i] = x;
return;
}
}
int main(){
int i,sum2 = 0;
scanf("%d",&n);
for (i = 0; i<n; i++)
scanf("%d",&a[i]);
for (i = 1; i<n; i++) {
int x = findMin();
Delete(x);
int y = findMin();
Delete(y);
add(x+y);
sum2+=x+y;
}
printf("%d\n",sum2);
}
这里注明一下:删除其实就是把现在这个数组里这个值(不一定是之前取的那个数)给赋值为非常大,这样下次寻找最小值就不会找到他。
如果有添加,那么之前一定有删除,直接把添加的值放在删除的值的地方就行了。
Max一定要特别大,要不然,最大值测试用例时,x+y的值甚至会大过Max,这样就出错了。
这个实现就很耗时了,算是锻炼思维把。