您的位置:首页 > 其它

优先队列(3道优先队列问题)

2017-04-14 19:30 225 查看
优先队列是一种十分强大的数据结构,它保持了一种动态的有序性,对于不断改变有入队的操作,而又需要某种最大或最小的操作的问题是再合适不过了,通常优先队列的实现是由最小堆或者最大堆完成的,并通过堆排序保持队列的有序性,模拟队列的结构,在实际比赛中要写一个堆排序还是要一定的时间的,但是stl中queue容器中已经可以实现优先队列,下面以三道基本的题目来演示priority_queue的作用。  

  

聪明的木匠    

Time Limit: 1000ms, Special Time Limit: 2500ms, Memory Limit: 32768KB    

Total submit users: 23, Accepted users: 10    

Problem 10611 : No special judgement    

Problem description    

    最近,一位老木匠遇到了一件非常棘手的问题。他需要将一根非常长的木棒切成N 段。每段的长度分别为 L1 ,L2 ,…,LN ( 1≤L1 ,L2 ,…,LN ≤1000 ,且均为整数)个长度单位。 ∑Li (i=1,2,…,N) 恰好就是原木棒的长度。我们认为切割时仅在整数点处切且没有木材损失。   

  木匠发现,每一次切割花费的体力与该木棒的长度成正比,不妨设切割长度为 1 的木棒花费 1 单位体力。例如,若 N=3 , L1 =3,L2 =4,L3 =5 ,则木棒原长为 12 ,木匠可以有多种切法,如:先将 12 切成 3+9. ,花费 12 体力,再将 9 切成 4+5 ,花费 9 体力,一共花费 21 体力;还可以先将 12 切成 4+8 ,花费 12 体力,再将 8 切成 3+5 ,花费 8 体力,一共花费 20 体力。显然,后者比前者更省体力。   

  那么,木匠至少要花费多少体力才能完成切割任务呢?   

  

   

Input    

  输入数据的第一行为一个整数N(2≤N≤150,000) ;   

在接下来的 N 行中,每行为一个整数 Li (1≤Li ≤1000) 。   

  

   

Output    

  输出数据仅有一行,为一个整数,表示木匠最少要花费的体力。测试数据保证这个整数不大于231 -1 。   

  

   

Sample Input    

4  

3  

5  

7  

11  

   

Sample Output    

49   

Problem Source    

  2010年河北大学程序设计竞赛   

   

  

   

  

最优的方法是每次切出最小的合并,显然要使用优先队列;  

  

[cpp:firstline[1]] view plaincopyprint?#include <iostream>     

#include <queue>     

struct cmp    

{    

    bool operator ()(const int &i,const int &j)    

    {    

        return i>j;    

    }    

};    

using namespace std;    

int main()    

{    

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

    int n;    

    while(cin>>n)    

    {    

        for(int i=0;i<n;i++)    

        {    

            int key;    

            scanf("%d",&key);    

            s.push(key);    

        }    

        int sum=0;    

        while(n>=2)    

        {    

            int a,b;    

            a=s.top();    

            s.pop();    

            b=s.top();    

            s.pop();    

            s.push(a+b);    

            //cout<<a<<' '<<b;     

            sum+=a+b;    

            n--;    

        }    

        cout<<sum<<endl;    

    }    

    return 0;    

        

}    

#include <iostream>  

#include <queue>  

struct cmp  

{  

    bool operator ()(const int &i,const int &j)  

    {  

        return i>j;  

    }  

};  

using namespace std;  

int main()  

{  

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

    int n;  

    while(cin>>n)  

    {  

        for(int i=0;i<n;i++)  

        {  

            int key;  

            scanf("%d",&key);  

            s.push(key);  

        }  

        int sum=0;  

        while(n>=2)  

        {  

            int a,b;  

            a=s.top();  

            s.pop();  

            b=s.top();  

            s.pop();  

            s.push(a+b);  

            //cout<<a<<' '<<b;  

            sum+=a+b;  

            n--;  

        }  

        cout<<sum<<endl;  

    }  

    return 0;  

      

}  

   

  

   

  

【问题描述】  

在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。  

因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。  

例如有3种果子,数目依次为1,2,9。可以先将 1、2堆合并,新堆数目为3,耗费体力为3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为 12。所以多多总共耗费体力=3+12=15。可以证明15为最小的体力耗费值。  

【输入文件】  

输入文件fruit.in包括两行,第一行是一个整数n(1 <= n <= 10000),表示果子的种类数。第二行包含n个整数,用空格分隔,第i个整数ai(1 <= ai <= 20000)是第i种果子的数目。  

【输出文件】  

输出文件fruit.out包括一行,这一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于231。  

【样例输入】  

3  

1 2 9  

【样例输出】  

15  

【数据规模】  

对于30%的数据,保证有n <= 1000;  

对于50%的数据,保证有n <= 5000;  

对于全部的数据,保证有n <= 10000。   

  

   

  

合并的最优方法是合并最小的两堆,通过优先队列就可以轻松实现;  

  

[cpp:firstline[1]] view plaincopyprint?#include <iostream>     

#include <queue>     

struct cmp    

{    

    bool operator ()(const int &i,const int &j)    

    {    

        return i>j;    

    }    

};    

using namespace std;    

int main()    

{    

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

    int n;    

    while(cin>>n)    

    {    

        for(int i=0;i<n;i++)    

        {    

            int key;    

            scanf("%d",&key);    

            s.push(key);    

        }    

        int sum=0;    

        while(n>=2)    

        {    

            int a,b;    

            a=s.top();    

            s.pop();    

            b=s.top();    

            s.pop();    

            s.push(a+b);    

            //cout<<a<<' '<<b;     

            sum+=a+b;    

            n--;    

        }    

        cout<<sum<<endl;    

    }    

    return 0;    

        

}    

#include <iostream>  

#include <queue>  

struct cmp  

{  

    bool operator ()(const int &i,const int &j)  

    {  

        return i>j;  

    }  

};  

using namespace std;  

int main()  

{  

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

    int n;  

    while(cin>>n)  

    {  

        for(int i=0;i<n;i++)  

        {  

            int key;  

            scanf("%d",&key);  

            s.push(key);  

        }  

        int sum=0;  

        while(n>=2)  

        {  

            int a,b;  

            a=s.top();  

            s.pop();  

            b=s.top();  

            s.pop();  

            s.push(a+b);  

            //cout<<a<<' '<<b;  

            sum+=a+b;  

            n--;  

        }  

        cout<<sum<<endl;  

    }  

    return 0;  

      

}  

   

  

   

  

删除最小值    

Time Limit: 1000ms, Special Time Limit: 2500ms, Memory Limit: 32768KB    

Total submit users: 8, Accepted users: 8    

Problem 10604 : No special judgement    

Problem description    

  序列A 中有 N 个元素,序列 B 中也有 N 个元素,依次将序列 B 中的元素移进序列 A ,对于每次移进元素,首先在一行输出序列 A 中的最小值,然后在 A 在加入该元素,接着在序列 B 中删除该元素,接着在序列 A 中删除刚才输出的最小值。  

  

   

Input    

  共三行,第一行给出元素数目N ,第二行给出 A 中的原始 N 个元素,第三行给出 B 中的原始 N 个元素。 1 ≤ n ≤ 10000 ,每个元素值范围为 [0 , 100000] 。  

  

   

Output    

  在每次将B中的元素移入A之前,在一行里输出A中所有元素的最小值。  

  

   

Sample Input    

3  

3 9 6  

5 2 10  

   

Sample Output    

3  

5  

2  

   

  

这道题目跟到模拟题目差不多……  

  

[cpp:firstline[1]] view plaincopyprint?#include <iostream>     

#include <queue>     

struct cmp    

{    

    bool operator ()(const int &i,const int &j)    

    {    

        return i>j;    

    }    

};    

using namespace std;    

int main()    

{    

    int b[10003];    

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

    int n;    

    while(cin>>n)    

    {    

        for(int i=0;i<n;i++)    

        {    

            int key;    

            scanf("%d",&key);    

            s.push(key);    

                

        }    

        for(int i=0;i<n;i++)    

        {    

            scanf("%d",&b[i]);    

        }    

        for(int j=0;j<n;j++)    

        {    

                

            //cout<<b[j]<<endl;     

            printf("%d/n",s.top());    

            s.pop();    

            s.push(b[j]);    

                

        }    

            

     }    

    return 0;    

        

}    

#include <iostream>  

#include <queue>  

struct cmp  

{  

    bool operator ()(const int &i,const int &j)  

    {  

        return i>j;  

    }  

};  

using namespace std;  

int main()  

{  

    int b[10003];  

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

    int n;  

    while(cin>>n)  

    {  

        for(int i=0;i<n;i++)  

        {  

            int key;  

            scanf("%d",&key);  

            s.push(key);  

              

        }  

        for(int i=0;i<n;i++)  

        {  

            scanf("%d",&b[i]);  

        }  

        for(int j=0;j<n;j++)  

        {  

              

            //cout<<b[j]<<endl;  

            printf("%d/n",s.top());  

            s.pop();  

            s.push(b[j]);  

              

        }  

          

     }  

    return 0;  

      

}  

   

  

以上三道题目如果掌握优先队列再去解答十分简单,做这种优先队列的题目,如果发现是使用优先队列的就很简单了(说的这都是废话!)  

  

stl中的优先队列的模板:  

  

#include <queue>  

  

priority_queue <int> q;  

  

这是按照从大到小的队列;  

  

#include <queue>  

  

struct cmp  

  

{  

  

    bool operator ()(const int &i,const int &j)  

  

    {  

  

        return i>j;  

  

    }  

  

};  

  

priority_queue <int> q;  

  

这是从小到大的优先队列;  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  优先队列