• nyoj55-懒省事的小明(优先队列排序,set)


    懒省事的小明
    时间限制:3000 ms  |  内存限制:65535 KB 
    难度:3
    描述       小明很想吃果子,正好果园果子熟了。在果园里,小明已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。小明决定把所有的果子合成一堆。 因为小明比较懒,为了省力气,小明开始想点子了:
      每一次合并,小明可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。小明在合并果子时总共消耗的体力等于每次合并所耗体力之和。 
       因为还要花大力气把这些果子搬回家,所以小明在合并果子时要尽可能地节省体力。假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使小明耗费的体力最少,并输出这个最小的体力耗费值。 
       例如有3种果子,数目依次为1,2,9。可以先将1、2堆合并,新堆数目为3,耗费体力为3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为12。所以小明总共耗费体力=3+12=15。可以证明15为最小的体力耗费值。

    输入第一行输入整数N(0<N<=10)表示测试数据组数。接下来每组测试数据输入包括两行,第一行是一个整数n(1<=n<=12000),表示果子的种类数。第二行包含n个整数,用空格分隔,第i个整数ai(1<=ai<=20000)是第i种果子的数目。 输出每组测试数据输出包括一行,这一行只包含一个整数,也就是最小的体力耗费值。

    样例输入

    1


    1 2 9

    样例输出

    15

    排序题,每次把最小的两个数加起来,把这个和放入原来的序列中重新排序。用sort会超时,所以想到用set容器。

    set是一种自动从小到大排序的容器,有很多函数可以用比如:

    begin()        ,返回set容器的第一个元素
    
    end()      ,返回set容器的最后一个元素
    
    clear()          ,删除set容器中的所有的元素
    
    empty()    ,判断set容器是否为空
    
    max_size()   ,返回set容器可能包含的元素最大个数
    
    size()      ,返回当前set容器中的元素个数
    
    rbegin     ,返回的值和end()相同
    
    rend()     ,返回的值和rbegin()相同

    还有:

    lower_bound(key_value) ,返回第一个大于等于key_value的定位器
    
    upper_bound(key_value),返回最后一个大于等于key_value的定位器

    但是这些函数对这个题目来说可能没有太大的作用,因为set里面不能放重复的元素,所以这个时候就会想到要用队列或者multiset。

    但是multiset;

    #include<set>
    #include<map>
    #include<stack>
    #include<queue>
    #include<math.h>
    #include<vector>
    #include<string>
    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<algorithm>
    #define mem(a,b) memset(a,b,sizeof(a))
    #define maxn 12005
    #define maxm 100005
    #define mod 1000000007
    #define ll long long
    #define inf 0x3f3f3f3f
    using namespace std;
    ll a[maxn];
    int main(){
        int t;
        scanf("%d",&t);
        while(t--){
            int n;
            multiset<ll>s;s.clear();
            scanf("%d",&n);
            for(int i=0;i<n;i++){
                cin>>a[i];
                s.insert(a[i]);
            }
            if(n==1){cout<<a[0]<<endl;continue;}
            ll ans=0;
            for(int i=0;i<n-1;i++){
                int a=*s.begin();s.erase(s.begin());
                int b=*s.begin();s.erase(s.begin());
                int c=a+b;
                s.insert(c);
                ans+=c;
            }
            printf("%lld
    ",ans);
        }
    }  

    优先队列:

    数从大到小排序:

    1.priority_queue<int>q ;(普通用法)
    2.priority_queue<int,vector<int>,less<int> >q ;(less可以换成其他的函数,也可以自定义)
    3.struct cmp{  
    bool operator()(int x,int y)  
         {  
        return x<y;    
         }  
    };    
    priority_queue<int,vector<int>,cmp >q ;  (把2的less自定义)。

    数的从小到大排序:(由于优先队列是默认从大到小,想要从小到大排的话就要有个函数)

    1.priority_queue<int,vector<int>,greater<int> >q ;
    2.struct cmp{  
    bool operator()(int x,int y)  
         {  
        return x>y;    
         }  
    };    
    priority_queue<int,vector<int>,cmp >q ; 
    结构体的排序:


    struct node {  
       int x,y;  
       friend bool operator < (node a, node b)  
       {  
           return a.x>b.x;    //x小的优先级高。  
       }  
    };  
    (只是重载运算符的方法不一样。)


    struct node{  
    int x,y;  
     bool operator < (const node &b) const{  //不能重载大于号。
           return x>b.x;     //这个是按x值从小到大排序,把小于号换成大于号可以实现从大到小。
         };
    };   
    priority_queue<node>q; 
    那么这个题就解决了。使用任何一种从小到大的排序方法都可以。


    #include<map>
    #include<set>
    #include<queue>
    #include<math.h>
    #include<vector>
    #include<string>
    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<algorithm>
    #define inf 0x3f3f3f
    #define ll long long
    #define maxn 130005
    using namespace std;
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            priority_queue<ll,vector<ll>,greater<ll> >q;
            int n;ll a;
            scanf("%d",&n);
            for(int i=0;i<n;i++)
            {
                scanf("%lld",&a);
                q.push(a);
            }
            if(n==1)
            {
                cout<<a<<endl;
                continue;
            }
            ll ans=0;
            for(int i=0;i<n-1;i++)
            {
                ll x,y,z;
                x=q.top();q.pop();
                y=q.top();q.pop();
                z=x+y;q.push(z);
                ans+=z;
            }
            cout<<ans<<endl;
        }
    }





  • 相关阅读:
    【TYVJ1728】【洛谷P3369】—普通平衡树(Splay写法)
    【BZOJ2388】—旅行规划(分块+凸包)
    【BZOJ3674】—可持久化并查集加强版(可持久化并查集)
    【模板】树链剖分+换根
    【CQOI2007】【BZOJ1257】【洛谷P2261】余数求和(整除分块)
    Old Driver Tree(ODT 老驱动树)
    【CodeForces-896C】— Willem, Chtholly and Seniorious(ODT老驱动树)
    【BZOJ2238】—MST(树链剖分+最小生成树)
    13.PHP_ThinkPHP
    Win64 驱动内核编程-33.枚举与删除对象回调
  • 原文地址:https://www.cnblogs.com/da-mei/p/9053279.html
Copyright © 2020-2023  润新知