1. 程式人生 > >NOIP提高組2004 合併果子(優先佇列排序)

NOIP提高組2004 合併果子(優先佇列排序)

從oj上看到一道問題,合併果子,題意如下:

1171.合併果子
Time Limit: 1000 MS Memory Limit: 32768 KB
Total Submission(s): 77 Accepted Submission(s): 18
Description
在一個果園裡,多多已經將所有的果子打了下來,而且按果子的不同種類分成了不同的堆。多多決定把所有的果子合成一堆。
每一次合併,多多可以把兩堆果子合併到一起,消耗的體力等於兩堆果子的重量之和。可以看出,所有的果子經過n-1次合併之後,就只剩下一堆了。多多在合併果子時總共消耗的體力等於每次合併所耗體力之和。
因為還要花大力氣把這些果子搬回家,所以多多在合併果子時要儘可能地節省體力。假定每個果子重量都為1,並且已知果子的種類數和每種果子的數目,你的任務是設計出合併的次序方案,使多多耗費的體力最少,並輸出這個最小的體力耗費值。
例如有3種果子,數目依次為1,2,9。可以先將1、2堆合併,新堆數目為3,耗費體力為3。接著,將新堆與原先的第三堆合併,又得到新的堆,數目為12,耗費體力為12。所以多多總共耗費體力=3+12=15。可以證明15為最小的體力耗費值。
Input
輸入包括兩行,第一行是一個整數n(1<=n<=10000),表示果子的種類數。第二行包含n個整數,用空格分隔,第i個整數ai(1<=ai<=20000)是第i種果子的數目。
Output
輸出包括一行,這一行只包含一個整數,也就是最小的體力耗費值。輸入資料保證這個值小於231。
Sample Input
3
1 2 9
Sample Output
15

乍一看感覺很簡單,無非是把所有資料按升序排列然後進行簡單加和運算,但是wa
後來發現其實問題在於合併之後的數不一定是最小的數,所以每次合併之後都要進行重新排序,然後必定會超時。。。

本來以為是一道水題,搜了搜題解,好像是關於優先佇列的(選擇排序也能做出來),正好搜了搜關於優先佇列的知識,優先佇列的排序,應用一下。

先掛程式碼

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map> #include<queue> #include<cmath> using namespace std; struct cmp { int m; friend bool operator < (cmp a, cmp b) { return a.m > b.m; } }; int main() { priority_queue<cmp>ans; cmp a,b; int n, sum = 0; cin>>n; for(int
i = 0; i < n; i ++) { cin>>a.m; ans.push(a); } for(int i = 0; i < n - 1; i ++) { a = ans.top(),ans.pop(); b = ans.top(),ans.pop(); sum += a.m + b.m; a.m += b.m; ans.push(a); } cout<<sum<<endl; return 0; }

每次都把最小的定位優先順序高的
這樣就不用每次排序,問題迎刃而解

看了很多大神都是把優先佇列排序放在結構體裡進行,也很方便

這裡說兩種我用著順手的排序方式
①:

struct cmp
{
    int m;
    friend bool operator < (cmp a, cmp b) {
       return a.m > b.m;
   }
};//從小到大排列 (用 > 表示從小到大)

看到大神說②和這個是一樣的
②:

struct cmp{  
int x,y;  
};  
bool operator(const cmp &a,const cmp &b)  
{  
return a.x>b.x;  
};  


priority_queue<cmp>ans;  

①和②都是對結構體進行過載操作符

③沒找到他的名字,但是也是ac的程式碼
③:

struct cmp
{
    int m;
    bool operator < (const cmp &d)
    const
   {
       return d.m < m;
   }
};//同為從小到大排列

還有④自定義優先順序
④:

struct cmp{  
  bool operator()(int a,int b)  
{  
    return a>b;   //x小的優先順序高。  
}  
};  

priority_queue<int,vector<int>,cmp>ans;  

所以學會了嗎,你?
然後再來一道題,看到有一道題和這個一樣的
1501.Problem_J

Time Limit: 2000 MS Memory Limit: 32768 KB
Total Submission(s): 78 Accepted Submission(s): 28
Description
So long coding time make ChaoChao be more nonsense. In order to spend the boring time, ChaoChao plan to practice his cooking stills.
Now, CC wants to make N foods. The i-th food need a[i] unit meat, but CC find that there is only a whole meat and he need to consume energy to cut meat. Consumption value is equal to the size of the cut meat. For example, there is a 21 units meat, so CC will consume 21 energy to cut it. CC wants to cut meat into N small meat. He wants to know the minimum number of the energy he need.(The size of the meat bought is equal to the sum of N pieces of meat.)
INPUT
The first line is a number N (1 ≤ N ≤ 20000) identified the number of small meat.

Then next N lines, each line contains one number a[i](1 ≤ a[i] ≤ 50000) means a[i] units of the i-th meat.
Input
The first line is a number N (1 ≤ N ≤ 20000) identified the number of small meat.

Then next N lines, each line contains one number a[i](1 ≤ a[i] ≤ 50000) means a[i] units of the i-th meat.
Output
The minimum number of the energy.
Sample Input
3
8
5
8
Sample Output
34
連蒙帶猜可以讀懂題意,其實就是合併果子,用近乎一樣的程式碼ac了

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
using namespace std;
struct cmp
{
    long long m;
    friend bool operator < (cmp a, cmp b) {
       return a.m > b.m;
   }
};
int main()
{
    priority_queue<cmp>ans;
    cmp a,b;
    long long n, sum = 0;
    while(scanf("%lld",&n)!=EOF){
            sum = 0;
    for(long long i = 0; i < n; i ++)
    {
        cin>>a.m;
        ans.push(a);
    }
    for(long long i = 0; i < n - 1; i ++)
    {
        a = ans.top(),ans.pop();
        b = ans.top(),ans.pop();
        sum += a.m + b.m;
        a.m += b.m;
        ans.push(a);
    }
    cout<<sum<<endl;
    while(!ans.empty())
        ans.pop();
    }
    return 0;
}

sdnuoj1412.Huffuman樹用一樣的程式碼也是能ac,,怎麼那麼多一樣的題啊,這oj是水。。。
其實就是一樣,把同類題歸總一下有空看看

另 佇列不能直接清空,搜了搜佇列清空方式,多次呼叫佇列時會用到

    //方法一,遍歷出佇列
    priority_queue<int>q;
    while(!q.empty())
        q.pop();


    //方法二,用空的佇列物件賦值
    q = priority_queue<int>();


    //方法三,使用swap定義空陣列(效率最高)
    void clear(priority_queue<int> &q)
    {
        priority_queue<int>empty;
        swap(empty,q);
    }