HDU - 6003 Problem Buyer题解(贪心选择算法,鸽巢原理,优先队列维护)

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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值