HDU - 6003 Problem Buyer題解(貪心選擇演算法,鴿巢原理,優先佇列維護)

retrogogogo發表於2020-12-22

HDU - 6003 Problem Buyer題解(貪心選擇演算法,鴿巢原理,優先佇列維護)

HDU6003原題點這裡

16年的ccpc final題,題目不長,但是讀題對於我這種蒟蒻還是看了半天,讀懂後大概推測是貪心演算法,用優先佇列維護一個題目區間能夠AC。
在這裡插入圖片描述
在這裡插入圖片描述


具體題解和分析鴿了,以後用空再寫。


稍微加了點註釋希望有幫助:

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
const int inf = 0x3f3f3f3f;
clock_t START, END;
struct difficultyRange {
	int l, r;
    bool operator < (const difficultyRange& t)const {
        return (l == t.l) ? (r > t.r) : (l < t.l);//l升序,l相等時r降序(其實r怎麼排序都無所謂)
    }
}dr[100010];
int main() {

    std::ios::sync_with_stdio(false);//不關閉同步流會使讀取速度過慢,這題經過測試只有關閉才能ac

    int T, N, M, c[100010];
    cin >> T;

    for (int ii = 1; ii <= T; ii++) {
        //資料輸入
        cin >> N >> M;
        for (int i = 1; i <= N; i++) {
            cin >> dr[i].l >> dr[i].r;
        }
        for (int i = 1; i <= M; i++) {
            cin >> c[i];
        }
        START = clock();
        //排序題庫和題
        sort(dr + 1, dr + 1 + N);
        sort(c + 1, c + 1 + M);

        int Max = -inf;
        int j = 1;
        priority_queue<int, vector<int>, greater<int> > Q;//存放當前能夠滿足該題的區間的右端(隊首為最小右端)

        for (int i = 1; i <= M; i++) {//遍歷每一個題目,確定 1.其對應題庫內題目 以及 2.其題庫內的最小購買數
          
            //這倆個while迴圈能保證佇列內永遠是此時題目所符合的題庫範圍
            while (!Q.empty() && Q.top() < c[i])
                Q.pop();//由於此時的題目難度更高了,可能原來的左端會不滿足,這裡將不滿足的題目出隊
            while (j <= N && dr[j].l <= c[i]) {
                if (dr[j].r >= c[i]) {
                    Q.push(dr[j].r);//將滿足條件的題庫內題目的右端入隊
                }
                j++;
            }

            Max = max(Max, N - (int)Q.size() + 1);//Q.size()是題庫內滿足我們要出的題目的難度範圍的題目個數,N-size+1即最小的題庫選擇數量,

            if (Max > N)
                break;
            if (!Q.empty())
                Q.pop();//將右端最小的值貪心選擇掉,接下來這個題目範圍不能繼續去匹配我們要出的題目
        }

        if (Max > N)
            cout << "Case #" << ii << ": IMPOSSIBLE!" << endl;
        else
            cout << "Case #" << ii << ": " << Max << endl;


        END = clock();
        double endtime = (double)(END - START) / CLOCKS_PER_SEC;
        cout << "Total time:" << endtime * 1000 << "ms" << endl;
    }

    return 0;
}

相關文章