未知:选择困难症——题解+优先队列

勇者是一个强迫症,而且又很抠门(虽然他有钱),每次点的菜系一个也不能少。
每次都问饭店老板第k小的组合是什么,店老板答错了了勇者还会发飙。
于是店老板撂下一句mmp,然后找到了路由器。


题目描述
又到吃饭时间,Polo 面对饭堂里琳(fei)琅(chang)满(keng)目(die)的各种食品,又陷入了痛苦的抉择中:该是吃手(jiao)打肉饼好呢,还是吃豆(cai)角(chong)肉片好呢?嗯……又不是天秤座怎么会酱紫呢?
具体来说,一顿饭由M 个不同的部分组成(荤菜,素菜,汤,甜品,饮料等等),Polo 要在每个部分中选一种作为今天的午饭。俗话说的好,永远没有免费的午餐,每种选择都需要有一定的花费。长者常常教导我们,便宜没好货,最便宜的选择估计比较坑爹,可囊中羞涩的Polo 还要把钱省下来给某人买生日礼物,这该怎么办呢?
于是一个折中方案出来了:第K 便宜的组合要花多少钱?这就要靠你了。
输入
第一行两个数M,K,含义如上所述。
接下来M 行,先是一个整数Ai,表示第i 个部分有多少种选择。接下来用空格分开的Ai 个整数表示每种选择的价格。
输出
一行一个整数表示答案。

样例输入
2 2
2 1 3
2 2 2
样例输出
3
提示
【样例解释】

最便宜的选择是第一部分选择1 块钱的,第二部分选择2 块的。但由于第二部分里2 块钱有两种不同的选择,所以第二便宜的总花费仍然是3 块。


好的虽然很不想写优先队列……但这题手写优先队列……臣妾实在做不到(一个小时奋斗无果,只好去自学优先队列函数了TAT)
那么先说优先队列函数
定义:队列里的元素按照重要性动态的排序就是优先队列。无特殊说明,元素数字越大,越重要。
使用:先#include然后priority_queue q;(类型可改)
函数:q.push(i)队列加入一个数i;
q.pop()弹出最重要的元素;
n=q.top()最重要的元素;
q.size()元素个数;
好知道这些就够了。

那么这个魔(题)法(解)其实很简单:
1.对数据由小到大排序。
2.数组dui[]表示从上到下依次累计和,永远保留最小的k个。
3.输出第k个。
优化:
1.只需要k个数,所以m=1时只需要在dui里面存min(a[1],k)即可。
2.由第1可知当dui[p]+b[i][j]大于了队列最大值,那么后面所有的dui[p]+b[i][j]一定大于最大值,所以直接跳出。(正确性不予证明)

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int a[11];
long long b[11][500001];
long long dui[1000000];
priority_queue<long long> q;
int main(){
    int m,k;
    scanf("%d%d",&m,&k);
    for(int i=1;i<=m;i++){
        scanf("%d",&a[i]);
        for(int j=1;j<=a[i];j++){
            scanf("%lld",&b[i][j]);
        }
        sort(b[i]+1,b[i]+a[i]+1);
    }
    int tot=min(a[1],k);
    for(int i=1;i<=tot;i++){
        dui[i]=b[1][i];
    }
    for(int i=2;i<=m;i++){
        long long maxn=21000000000000;
        for(int j=1;j<=a[i];j++){
            for(int p=1;p<=tot;p++){
                if(dui[p]+b[i][j]>maxn){
                    break;
                }
                if(q.size()<k){
                    q.push(dui[p]+b[i][j]);
                    if(q.size()==k){
                        maxn=q.top();
                    }
                }else{
                    if(dui[p]+b[i][j]<maxn){
                        q.pop();
                        q.push(dui[p]+b[i][j]);
                        maxn=q.top();
                    }
                }
            }
        }
        tot=0;
        while(!q.empty()){
            tot++;
            dui[tot]=q.top();
            q.pop();
        }
        for(int p=1;p<=tot/2;p++){
            long long t;
            t=dui[p];
            dui[p]=dui[tot-p+1];
            dui[tot-p+1]=t;
        }
    }
    printf("%lld",dui[k]);
    return 0;
}
发布了59 篇原创文章 · 获赞 4 · 访问量 1万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章