优先队列解贪心后悔类问题(HDU 1789、AcWing 145、洛谷 P4053)

HDU 1789:Doing Homework again

代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<bits/stdc++.h>

using namespace std;
#define int long long
const int N = 1010;
int n;
bool st[N];

struct node
{
    int redu, ddl;
    bool operator< (const node& x)const {
        if (ddl == x.ddl) return redu > x.redu;
        return ddl < x.ddl;
    }
} nod[N];

struct nodeI
{
    int redu, ddl;
    bool operator< (const nodeI& x)const {
        return redu > x.redu;
    }
};


signed main()
{
    int T; cin >> T;

    while (T--)
    {
        memset(st, false, sizeof st);
        int sum = 0;
        cin >> n;
        for (int i = 1; i <= n; ++i)
        {
            int ddl; cin >> ddl;
            nod[i].ddl = ddl;
        }

        for (int i = 1; i <= n; ++i)
        {
            int redu; cin >> redu;
            nod[i].redu = redu;
            sum += redu;
        }

        sort(nod + 1, nod + n + 1);

        priority_queue<nodeI> heap;

        int day = 1, res = 0;

        for (int i = 1; i <= n; ++i)
        {
            int d = nod[i].ddl, r = nod[i].redu;
            if (day <= d)
            {
                heap.push({ r, d });
                res += r;
                ++day;
            }
            else if(day > d)
            {
                auto tmp = heap.top();
                int dd = tmp.ddl, rr = tmp.redu;
                if (rr < r)
                {
                    heap.pop(), res -= rr;
                    heap.push({ r, d }), res += r;
                }
                else continue;
            }
        }

        //cout << sum << ' ' << res << '\n';
        cout << sum - res << '\n';
    }


    return 0;
}

AcWing 145:超市

代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include <bits/stdc++.h>

using namespace std;
#define int long long
const int N = 10010;
int n;
struct node
{
	int p, d;
	bool operator< (const node& x)const {
		if (d == x.d) return p > x.p;
		return d < x.d;
	}
} nod[N];

struct nd
{
	int val, time;
	bool operator< (const nd& x)const {
		return val > x.val;
	}
};

signed main()
{
	int T = 1; //cin >> T;

	while (T--)
	{
		while (cin >> n)
		{
			if (!n)
			{
				puts("0");
				continue;
			}

			for (int i = 1; i <= n; ++i) cin >> nod[i].p >> nod[i].d;
			sort(nod + 1, nod + n + 1);

			int day = 1;
			priority_queue<nd> heap;
			int res = 0;

			for (int i = 1; i <= n; ++i)
			{
				if (day <= nod[i].d) {
					heap.push({ nod[i].p, nod[i].d });
					res += nod[i].p;
					day++;
				}
				else {
					if (heap.size()){
						auto top = heap.top();
						if (top.val < nod[i].p) {
							res -= top.val;
							heap.pop();
							heap.push({ nod[i].p, nod[i].d });
							res += nod[i].p;
						}
					}
				}
			}

			cout << res << '\n';
		}
		
	}

	return 0;
}

洛谷 P4053 建筑抢修

代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include <bits/stdc++.h>

using namespace std;
#define int long long
const int N = 1.5e5 + 10;
int n;
struct node
{
	int use;
	int ddl;
	bool operator< (const node& x)const {
		if (ddl == x.ddl) return use < x.use;
		return ddl < x.ddl;
	}
} nod[N];

struct nd
{
	int use;
	int ddl;
	bool operator< (const nd& x)const {
		return use < x.use;
	}
};

signed main()
{
	int T = 1; //cin >> T;

	while (T--)
	{
		cin >> n;
		for (int i = 1; i <= n; ++i)
		{
			scanf("%lld%lld", &nod[i].use, &nod[i].ddl);
		}

		sort(nod + 1, nod + n + 1);

		int time = 0, cnt = 0;
		priority_queue<nd> heap;

		for (int i = 1; i <= n; ++i)
		{
			time += nod[i].use;
			if (time <= nod[i].ddl)
			{
				++cnt;
				heap.push({ nod[i].use, nod[i].ddl });
			}
			else
			{
				time -= nod[i].use;
				if (heap.top().use > nod[i].use && heap.size())
				{
					auto t = heap.top(); heap.pop();
					time -= t.use;
					time += nod[i].use;
					heap.push({ nod[i].use, nod[i].ddl });
				}
			}
		}

		cout << cnt << '\n';
	}

	return 0;
}
对于HDU4546问题,还可以使用优先队列(Priority Queue)来决。以下是使用优先队列法思路: 1. 首先,将数组a进行排序,以便后续处理。 2. 创建一个优先队列(最小堆),用于存储组合之和的候选值。 3. 初始化优先队列,将初始情况(即前0个数的组合之和)加入队列。 4. 开始从1到n遍历数组a的元素,对于每个元素a[i],将当前队列中的所有候选值取出,分别加上a[i],然后再将加和的结果作为新的候选值加入队列。 5. 重复步骤4直到遍历完所有元素。 6. 当队列的大小超过k时,将队列中的最小值弹出。 7. 最后,队列中的所有候选值之和即为前k小的组合之和。 以下是使用优先队列HDU4546问题的代码示例: ```cpp #include <iostream> #include <vector> #include <queue> #include <functional> using namespace std; int main() { int n, k; cin >> n >> k; vector<int> a(n); for (int i = 0; i < n; i++) { cin >> a[i]; } sort(a.begin(), a.end()); // 对数组a进行排序 priority_queue<long long, vector<long long>, greater<long long>> pq; // 最小堆 pq.push(0); // 初始情况,前0个数的组合之和为0 for (int i = 0; i < n; i++) { long long num = pq.top(); // 取出当前队列中的最小值 pq.pop(); for (int j = i + 1; j <= n; j++) { pq.push(num + a[i]); // 将所有加和结果作为新的候选值加入队列 num += a[i]; } if (pq.size() > k) { pq.pop(); // 当队列大小超过k时,弹出最小值 } } long long sum = 0; while (!pq.empty()) { sum += pq.top(); // 求队列中所有候选值之和 pq.pop(); } cout << sum << endl; return 0; } ``` 使用优先队列的方法可以有效地找到前k小的组合之和,时间复杂度为O(nklog(k))。希望这个法对你有所帮助!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值