POJ3253 Fence Repair

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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章