优先队列练习总结

1、合并果子
(fruit.pas/dpr/c/cpp)
【问题描述】 
    在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。 
    每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过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。 
2、最小函数值(minval)
【题目描述】
有n个函数,分别为F1,F2,...,Fn,定义Fi(x)=Aix2+Bix+Ci(x∈N∗(N*代表不含0的自然数)Fi(x)=Ai*x^2+Bi*x+Ci(x∈N∗)。给定这些Ai、Bi和Ci,请求出所有函数的所有函数值中最小的m个(如有重复的要输出多个)。
【输入】
第一行输入两个正整数n和m。
以下n行每行三个正整数,其中第i行的三个数分别位Ai、Bi和Ci。输入数据保证Ai≤10,Bi≤100,Ci≤10000,Ai≤10,Bi≤100,Ci≤10000。
【输出】
将这n个函数所有可以生成的函数值排序后的前m个元素。这m个数应该输出到一行,用空格隔开。
【输入样例】
3 10
4 5 3
3 4 5
1 7 1
【输出样例】
9 12 12 19 25 29 31 44 45 54
【提示】
【数据规模】
n,m≤10000n,m≤10000。
3、看病(hp.cpp)
【题目描述】
有个朋友在医院工作,想请BSNY帮忙做个登记系统。具体是这样的,最近来医院看病的人越来越多了,因此很多人要排队,只有当空闲时放一批病人看病。但医院的排队不同其他排队,因为多数情况下,需要病情严重的人优先看病,所以希望BSNY设计系统时,以病情的严重情况作为优先级,判断接下来谁可以去看病。
【输入】
第一行输入n,表示有n个操作。
对于每个操作,首先输入push或pop。
push的情况,之后会输入ai 和 bi,分别表示患者姓名和患者病情优先级。
pop后面没有输入,但需要你输出。
【输出】
对于pop的操作,输出此时还在排队人中,优先级最大的患者姓名和优先级。
表示他可以进去看病了。
如果此时没人在排队,那么输出”none”,具体可见样例。
【输入样例】
7
pop
push bob 3
push tom 5
push ella 1
pop
push zkw 4
pop
【输出样例】
none
tom 5
zkw 4
【提示】
【数据规模和约定】
1≤n≤100000,每个人的优先级都不一样,0≤优先级≤2000000000。
姓名都是小写字母组成的,长度小于20。
4、小明的账单(bill)
【题目描述】
小明在一次聚会中,不慎遗失了自己的钱包,在接下来的日子,面对小明的将是一系列的补卡手续和堆积的账单… 在小明的百般恳求下,老板最终同意延缓账单的支付时间。可老板又提出,必须从目前还没有支付的所有账单中选出面额最大和最小的两张,并把他们付清。还没有支付的账单会被保留到下一天。 请你帮他计算出支付的顺序。
【输入】
第1行:一个正整数N(N≤15,000),表示小明补办银联卡总共的天数。
第2行到第N+1 行:每一行描述一天中收到的帐单。先是一个非负整数M≤100,表示当天收到的账单数,后跟M个正整数(都小于1,000,000,000),表示每张帐单的面额。
输入数据保证每天都可以支付两张帐单。
【输出】
输出共N 行,每行两个用空格分隔的整数,分别表示当天支付的面额最小和最大的支票的面额。
【输入样例】
4
3 3 6 5
2 8 2
3 7 1 7
0
【输出样例】
3 6
2 8
1 7
5 7

5、踢石头(stone)
问题描述
编程集训,真累人!
课间,某君在操场上沿着笔直的跑道从左往右走着、散步休息……
看到有N个排成一直线的小石头,于是他无聊的踢了起来:
在他遇到第“奇数”块石头时,他会将其往前面踢,能踢多远在输入中会给出,而遇到第“偶数”个石头时不进行处理(不踢:略过)。当有多个石头在同一位置时,则先处理“射程”(踢下,石头往前移的距离)最短的石头。
然后他就这么一直往前走,边走边踢,直到前面已经没有任何石头时,这时候计算该群与出发点的距离。
输入 
第一行一个正整数N (0<N<=100,000),表示石头的个数
接下来有N行,每行两个整数,分别表示石头的位置Pi及其射程Di。Pi(0<=Pi<=100,000) 、Di(0<=Di<=1,000)
输出
前面没石头时,离出发点的距离 
输入样例一
2 
1 5 
2 4 
输出样例一
11

样例一解析
一开始的时候遇到的是第一个石头(1,5),他的坐标是1,然后往前踢了5个单位之后,坐标变成(6,5)
随后继续往前走,开始遇到第二个石头(2,4),忽略过。
然后继续往前走,遇到了第三个石头(6,5),即原第一个石头,但是它此时坐标为6。往前踢了5个单位之后,坐标变成(11,5),
继续往前走,一直走到坐标11时,遇到第四个石头(11,5),忽略。
前面已经没有石头了,因此此时离坐标原点的距离为11。

输入样例二
2 
1 5
6 6
输出样例二
12

数据规模 
在90%的数据中,1 ≤ N ≤ 3000; 
在100%的数据中,1 ≤ N ≤ 100000; 
保证所有输入数据中等级的值小于10^8,1 ≤ K ≤ N-1 。
6、黑匣子(blackbox)
问题描述 
  Black Box是一种原始的数据库。它可以存储一个整数数组,还有一个特别的变量i。最开始的时候Black Box是空的,而i等于0。这个Black Box要处理一串命令。 
  命令只有两种: 
   ADD(x):把x元素放进Black Box; 
   GET:i加1,然后输出Black Box中第i小的数。 
  记住:第i小的数,就是Black Box里的数按从小到大的顺序排序后的第i个元素。 
例如: 我们来演示一下一个有11个命令的命令串。(如下图所示) 
     
  现在要求找出对于给定的命令串的最好的处理方法。ADD和GET命令分别最多有200000个。 
现在用两个整数数组来表示命令串: 
  1、A(1),A(2),…A(M):一串将要被放进Black Box的元素。每个数都是绝对不超过2000000000的整数,M≤200000。例如上面的例子就是
A=(3,1,-4,2,8,-1000,2)。
  2、u(1),u(2),…u(N):表示第u(j)个元素被放进了Black Box里后就出现了一个GET命令。例如上面的例子中的u=(1,2,6,6)。 
  输入数据不用判错。 
输入 
第一行,两个整数,M,N。 
第二行,M个整数,表示A(1) …A(M)。 
第三行,N个整数,表示u(1)…u(N)。 
输出 
输出Black Box根据命令串所得出的输出串,一个数字一行。
输入样例 
7 4
3 1 -4 2 8 -1000 2
1 2 6 6
输出样例 
3
3
1
2
数据说明
对于30%的数据,M≤10000; 
对于50%的数据,M≤100000 
对于100%的数据,M≤200000 
7、鱼塘钓鱼(fishing)
【题目描述】
有N个鱼塘排成一排(N<100),每个鱼塘中有一定数量的鱼,N=5时,如下表:
第1分钟能钓到的鱼的数量(1..1000) 每过1分钟钓鱼数的减少量(1..100) 当前鱼塘到下一个相邻鱼塘需要的时间( 单位:分钟)
1 10 2 3
2 14 4 5
3 20 6 4
4 16 5 4
5 9 3 
即:在第1个鱼塘中钓鱼第1分钟内可钓到10条鱼,第2分钟内只能钓到8条鱼,……,第5分钟以后再也钓不到鱼了。从第1个鱼塘到第2个鱼塘需要3分钟,从第2个鱼塘到第3个鱼塘需要5分钟,…… 
给出一个截止时间T(T<1000),设计一个钓鱼方案,从第1个鱼塘出发,希望能钓到最多的鱼。假设能钓到鱼的数量仅和已钓鱼的次数有关,且每次钓鱼的时间都是整数分钟。
Input

输入有多组数据,每组数据共5行,分别表示:
第1行为N;
第2行为第1分钟各个鱼塘能钓到的鱼的数量,每个数据之间用一空格隔开;
第3行为每过1分钟各个鱼塘钓鱼数的减少量,每个数据之间用一空格隔开;
第4行为当前鱼塘到下一个相邻鱼塘需要的时间;
第5行为截止时间T;
Output

对于每组数据仅输出一个整数(不超过2^31-1),表示你的方案能钓到的最多的鱼。
Sample Input

5
10 14 20 16 9
2 4 6 5 3
3 5 4 4
14
Sample Output
76

T1~T5都是水题,代码直接贴上虽然说t2看不懂

T1

#include <cstdio>
#include <queue>

using namespace std;
priority_queue<int> Q;
int n,xs;

int main()
{
    freopen("fruit.in","r",stdin);
    freopen("fruit.out","w",stdout);
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&xs);
        Q.push(-xs);
    }int ans=0;
    while(Q.size())
    {
        int x=-Q.top();Q.pop();
        if(!Q.size())break;
        int y=-Q.top();Q.pop();
        ans+=x+y;
        Q.push(-(x+y));
    }
    printf("%d",ans);
}

T3

#include <iostream>
#include <cstdio>
#include <queue>

using namespace std;

struct node
{
    string n;int w;
    bool operator < (const node &rhs)const{
        return w<rhs.w;
    }
};
int n;
priority_queue<node> Q;

int main()
{
    freopen("hp.in","r",stdin);
    freopen("hp.out","w",stdout);
    cin>>n;
    while(n--)
    {
        string x,a;
        int y;
        cin>>a;
        if(a=="pop")
        {
            if(Q.size())
                cout<<Q.top().n<<" "<<Q.top().w<<"\n",Q.pop();
            else
                cout<<"none\n";
        }
        else
        {
            cin>>x>>y;
            Q.push({x,y});
        }
    }
    return 0;
}

T4

#include <bits/stdc++.h>
inline void read(int& x) {
  x=0;
  char ch=0;
  bool sign=false;
  while(!isdigit(ch)){ sign|=(ch=='-');ch=getchar();}
  while(isdigit(ch)) { x=x*10+(ch^48); ch=getchar();}
  x=sign?-x:x;
}
using namespace std;

int n,m;
map<long long,int> vis;
priority_queue<int> Q1,Q2;
int x;

int main()
{
    freopen("bill.in","r",stdin);
    freopen("bill.out","w",stdout);
    read(n);
    for(int i=1; i<=n; i++)
    {
        read(m);
        for(int i=1; i<=m; i++)
        {
            int x;
            read(x);
            Q1.push(x);Q2.push(-x);
        }
        printf("%d %d\n",-Q2.top(),Q1.top());
        Q2.pop();Q1.pop();
    }
    return 0;
}

T5

#include <cstdio>
#include <cctype>
#include <queue>

struct kl
{
    int p,d;
    bool operator < (const kl & rhs)const{
        return p>rhs.p||p == rhs.p && d>rhs.d;
    }
};
std::priority_queue<kl> P;
inline void read(int& x) {
  x=0;
  char ch=0;
  bool sign=false;
  while(!isdigit(ch)){ sign|=(ch=='-');ch=getchar();}
  while(isdigit(ch)) { x=x*10+(ch^48); ch=getchar();}
  x=sign?-x:x;
}

int n;
int x,y;
int ans;
int sum;

int main()
{
    freopen("stone.in","r",stdin);
    freopen("stone.out","w",stdout);
    read(n);
    for(int i=1; i<=n; i++)
    {
        read(x);read(y);
        P.push({x,y});
    }
    while(!P.empty())
    {
        kl temp=P.top();
        ans=temp.p;
        P.pop();
        sum++;
        if((sum%2))
        {
            P.push({temp.p+temp.d,temp.d});
        }
        else
        {
            continue;
        }
    }
    printf("%d",ans);
    return 0;
}

T5只打了个暴力,50分。

#include <iostream>
#include <cstdio>
#include <cctype>
#include <queue>

struct node
{
    int x;
    bool operator < (const node & rhs)const
    {
        return x>rhs.x;
    }
};

int n,m;
int num;
int a[200010];

inline void solve(int x)
{
    std::priority_queue<node> temp;
    for(int i=1; i<=x; i++)
    {
        //Q.push(-a[i]);
        temp.push({a[i]});
    }
    num++;
    int Temp=num-1;
    //printf("num=%d\n",Temp);
    for(int i=1; i<=Temp; i++)
    {
        temp.pop();
    }
    printf("%d\n",temp.top().x);
}

int main()
{
    freopen("blackbox.in","r",stdin);
    freopen("blackbox.out","w",stdout);
    int x;
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&a[i]);
    }
    for(int i=1; i<=m; i++)
    {
        scanf("%d",&x);
        solve(x);
    }
    return 0;
}

正解

尚未理解,待填坑

建立两个优先队列:最大堆a和最小堆b。最大堆a存放前i大的元素,最小堆b存放其它元素,且a.top()<=b.top() 。即每次输出最大堆a的队首元素。 进队:若当前序列的元素比最大堆a的队首元素小,则插入最大堆a,同时为了维护个数,把a的队首元素“移入”最小堆b。否则进入插入最小堆b。 时刻保持最大堆a元素个数与GET操作相对应,即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
priority_queue< int , vector<int> , less<int> >q1;
priority_queue< int , vector<int> , greater<int> >q2;
int num[200010],ord[200010],p[200010];
int m,n;
inline int read(){
    char ch=getchar(); int rt,ck=1;
    while (ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if (ch=='-'){
        ck=-1;
        ch=getchar();
    }
    rt=ch-'0'; ch=getchar();
    while (ch>='0'&&ch<='9'){
        (rt*=10)+=(ch-'0');
        ch=getchar();
    }
    return rt*ck;
}

int main(){
    int j=1,k;
    freopen("blackbox.in","r",stdin);
    freopen("blackbox.out","w",stdout);
    m=read(); n=read();
    for (int i=1;i<=m;i++) num[i]=read();
    for (int i=1;i<=n;i++) ord[i]=read();
    for (int i=1;i<=m;i++){
        if (!q1.empty()&&num[i]<q1.top()){
            q1.push(num[i]);
            q2.push(q1.top());
            q1.pop();
        }
        else{
            q2.push(num[i]);
        }
        while (i==ord[j]){
            q1.push(q2.top());
            printf("%d\n",q1.top());
            j++;
            q2.pop();

        }
    }
    return 0;
}

T6还没做

posted @ 2018-12-11 23:33  加固文明幻景  阅读(16)  评论(0编辑  收藏  举报  来源