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);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值