农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要N块木头,每块木头长度为整数Li个长度单位,于是他购买了一条很长的、能锯成N块的木头,即该木头的长度是Li的总和。
但是农夫自己没有锯子,请人锯木的酬金跟这段木头的长度成正比。为简单起见,不妨就设酬金等于所锯木头的长度。例如,要将长度为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
方式一:
堆(一种特殊的完全二叉树)还没用熟。。。c++的优先队列不会用,只是知道有这么个玩意,网上找了它的用法才写出来的,算是又了解了一项新的技能吧。这道题一看最少花费,就想到了哈夫曼树,也就是最优二叉树,但是我目前只是知道了它的用法,具体代码写了一部分,还有待学习,二叉树的前边还挺简单,比如遍历,构造等,一到应用,或者AVL树等就变得复杂了,有点担心。。。现在感觉学习它们理解思想只是掌握了百分之三十吧,剩下的还得需要实现了才能说这个数据结构我真的会了,路漫漫其修远兮。。。
附上参考和用到的知识的一些链接,希望对你有帮助
这个说了一下其在堆和排序中的不同
C++STL中的greater()和less()
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
int main(){
int n;
cin >> n;
int num;
priority_queue<int,vector<int>,greater<int>> qe;
for(int i = 0;i<n;i++){
cin >> num;
qe.push(num);
}
int sum = 0;
while(qe.size()>=2){
int a = qe.top();
qe.pop();
int b = qe.top();
qe.pop();
sum += (a+b);
qe.push(a+b);
}
cout << sum;
return 0;
}
方式二:
emmm,参考网上代码并做出修改,使用堆,插入时向上调整,删除时向下调整,使其永远满足最小堆,详见代码注释
#include <iostream>
using namespace std;
int h[10001];
int n;
//交换,传入的是编号,从1开始
void swap(int x,int y){
int tmp = h[x];
h[x] = h[y];
h[y] = tmp;
}
//向上调整函数,用于插入
void up(int i){
bool flag = false;//是否继续调整
if(i==1)
return;
while(i!=1&&!flag){//如果个数大于1且需要调整
if(h[i]<h[i/2])//如果此编号的值小于父结点,就交换
swap(i,i/2);
else
flag = true;//当前结点的值比父结点大,不再调整
i /= 2;//更新编号,如果继续调整,则应该从它的父结点开始调整
}
}
//向下调整,用于删除
void down(int i) {
int t;
bool flag = false;//作用同up函数
while(i*2<=n&&!flag){//如果有左儿子且需要调整
if(h[i]>h[i*2])//左儿子更小
t = i*2;
else
t = i;
if(2*i+1<=n){//如果有右儿子
if(h[t]>h[i*2+1])//右儿子更小
t = 2*i+1;
}
if(t!=i){//变化了,找到最终需要交换的了
swap(t,i);
i = t;//更新编号,用于下一次调整
}else{
flag = true;
}
}
}
//获取堆顶元素值,即取最小值
int getMin() {
int tmp;//保存当前最小值
tmp = h[1];
h[1] = h[n];//将最大值与堆顶值互换,用于将删除最小值之后的堆变为最小堆
n--;//删除后,元素个数减一
down(1);//由于当前堆顶元素是最大值,需要向下调整至符合最小堆,编号为1
return tmp;//返回调整前的堆顶值
}
int main() {
cin >> n;
int i;
int sum = 0;
for(i = 1;i<=n;i++) {
cin >> h[i];
up(i);//每插入一个数就向上调整
}
while(n!=1) {//只有一个值时就是最终的sum值,因为一个值无法再取出然后再相加再up
int a = getMin();
int b = getMin();
n++;//插入时个数+1
h[n] = a + b;
sum += h[n];
up(n);
}
cout << sum;
return 0;
}
下边是测试点,在PTA上有些题目集中有的可以找到原题,有时候不知道哪里错了可以在上边提交一遍找测试点,有的有,有的没有