未知:選擇困難症——題解+優先隊列

勇者是一個強迫症,而且又很摳門(雖然他有錢),每次點的菜系一個也不能少。
每次都問飯店老闆第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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章