NOIP提高组2004 合并果子(优先队列排序)

来源:互联网 发布:淘宝发物流怎么填单号 编辑:程序博客网 时间:2024/05/18 21:09

从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);    }
原创粉丝点击