http://poj.org/problem?id=3253
大致題意:
有一個農夫要把一個木板鉅成幾塊給定長度的小木板,每次鋸都要收取一定費用,這個費用就是當前鋸的這個木版的長度
給定各個要求的小木板的長度,及小木板的個數n,求最小費用
提示:
以
3
5 8 8爲例:
先從無限長的木板上鋸下長度爲 21 的木板,花費 21
再從長度爲21的木板上鋸下長度爲5的木板,花費5
再從長度爲16的木板上鋸下長度爲8的木板,花費8
總花費 = 21+5+8 =34
解題思路:
利用Huffman思想,要使總費用最小,那麼每次只選取最小長度的兩塊木板相加,再把這些“和”累加到總費用中即可
本題雖然利用了Huffman思想,但是直接用HuffmanTree做會超時,可以用優先隊列做
因爲樸素的HuffmanTree思想是:
(1)先把輸入的所有元素升序排序,再選取最小的兩個元素,把他們的和值累加到總費用
(2)把這兩個最小元素出隊,他們的和值入隊,重新排列所有元素,重複(1),直至隊列中元素個數<=1,則累計的費用就是最小費用
HuffmanTree超時的原因是每次都要重新排序,極度浪費時間,即使是用快排。
一個優化的處理是:
(1)只在輸入全部數據後,進行一次升序排序 (以後不再排序)
(2)隊列指針p指向隊列第1個元素,然後取出隊首的前2個元素,把他們的和值累計到總費用,再把和值sum作爲一個新元素插入到隊列適當的位置
由於原隊首的前2個元素已被取出,因此這兩個位置被廢棄,我們可以在插入操作時,利用後一個元素位置,先把隊列指針p+1,使他指向第2個廢棄元素的位置,然後把sum從第3個位置開始向後逐一與各個元素比較,若大於該元素,則該元素前移一位,否則sum插入當前正在比較元素(隊列中大於等於sum的第一個元素)的前一個位置
(3)以當前p的位置作爲新隊列的隊首,重複上述操作
錯誤代碼:
#include<iostream> //因爲每次切不一定就可以切出一塊所需的木板,
//可以先把整體切成兩部分再分別對這兩部分進行切割
#include<algorithm>
using namespace std;
int main()
{
int a[20010];
int i,n,ans,sum;
while(cin>>n)
{
for(i=0;i<n;++i)
{
cin>>a[i];
sum+=a[i];
}
sort(a,a+n);
for(i=n-1;i>0;--i)
{
ans+=sum;
sum-=a[i];
}
cout<<ans<<endl;
}
return 0;
}
華麗麗的。。。。。----思路都不正確,我以爲每次只要把最長的先切去所花費用就最短,這種想法是錯的
正確代碼:
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int main(void)
{
int n;
while(cin>>n)
{
int w[20001];
for(int p=1;p<=n;p++)
scanf("%I64d",&w[p]);
sort(w,w+n+1);
__int64 mincost=0;
for(int i=1;i<=n-1;i++) //每次枚舉餘下數列的前2個(最小)的元素,則i到n-1即可
{
__int64 sum=w[i]+w[i+1]; //此時w[i]和w[i+1]已經沒有用了
mincost+=sum;
for(int j=i+2;j<=n;j++) //尋找w[i]+w[i+1]即sum在餘下數列的合適位置,並插入
{
if(sum>w[j]) //sum大於當前元素
{
w[j-1]=w[j]; //當前元素前移一格
if(j==n) //sum大於最後的元素(即大於所有元素)
{
w[j]=sum; //插入到最後
break;
}
}
else
{
w[j-1]=sum; //插入到比sum大的第一個元素前面(此前的元素均被前移)
break;
}
}
}
printf("%I64d\n",mincost);
}
return 0;
}