農夫要修理牧場的一段柵欄,他測量了柵欄,發現需要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,這樣就出錯了。
這個實現就很耗時了,算是鍛鍊思維把。