K - Summer Vacation

文章描述了一种算法问题,每天可以选择一个工作并在完成后的特定天数获得奖励。初始的错误解法是先按奖励时间排序,然后从大到小选择。正确的解法是按时间从小到大排序,使用优先队列,在每一步选择当前可完成的工作中报酬最高的,以求在给定的天数内获得最大总奖励。
摘要由CSDN通过智能技术生成

【题目描述】

有一次性的工作可用。如果您接受第 -份工作并完成它,您将从您完成工作的那天起获得几天后的奖励。NiBi​,Ai

您一天最多可以接受并完成其中一项工作。

但是,您不能重新接受已经完成的工作。

找到您从今天起几天内可以获得的最高总奖励。M

您今天就可以开始工作了。

【输入】

  • 输入中的所有值都是整数。
  • 1≤N≤105
  • 1≤M≤105
  • 1≤Ai​≤105
  • 1≤Bi​≤104

【输出】

打印您最迟可以从今天起到第M天内获得的最高总奖励。

解题思路

题目大意是:每天可以选择一个工作并完成,但是工作完成了,并不会马上获得报酬,相当于工作完成后的第x天才收到报酬,所以要选择正确的工作顺序,在有限的天数内获得最大报酬。

这个题目首先思考错了:我用一个结构体存储天数和报酬,然后根据时间从小到大排序,在两个工作时间相同时,按照报酬大的放前面排序。然后将天数从大往小,排工作任务。此时忽略了一个问题,天数小的一直会被优先考虑,所以可能不能达到最大报酬的要求。

换一个计算方式,将结构体根据天数从小到大的顺序排序,然后用一层循环遍历给出的总天数m,其中ans是从零开始递增的结构体下标,里面是一层while循环:如果结构体中得到报酬的天数k[ans].a<=i,就将k[ans].b加入优先队列。

在当前天数i的情况下,加入优先队列的都是可以选择的工作任务,在这个前提下,选择队头,sum = sum + q.top();接着将它出队,继续下面的循环。这样就可以保证在每个天数要求下,选择最大报酬的工作。

代码如下

#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
struct node {
	int a;//天数
	int b;//报酬
	
}k[100005];
//按照获得报酬的时间长短排序(短的在前面)
//如果时间相同,报酬高的排在前面
bool cmp(struct node&q,struct node &w){
	if (q.a == w.a) {
		return q.b > w.b;
	}
	return q.a < w.a;
}
int main() {
    int n, m;
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        cin >> k[i].a >> k[i].b;
    }
    sort(k, k + n, cmp);
    //从后往前排工作,把花费时间小的先安排
    priority_queue<int> q;//用优先队列(优先队列把报酬按从大到小排列)
    int ans = 0;
    int sum = 0;
    //如果当前任务的天数小于剩余的天数,则表示可以完成它;就把他放到队列里面;(为什么都放里面呢,如果剩i天可以完成这些任务,那么剩余i+1天一定可以完成这些任务,所以只需要挑时间短,报酬高的即可)
    for (int i = 1; i <= m; i++) {
        //当限制天数为i时,这个工作可以完成,说明在i+1或者更长的天数都可以完成
        //此时把报酬保留在优先队列中,只有当天选择并做完的工作移除队列
        while (k[ans].a <= i && ans < n) {
            q.push(k[ans].b);
            ans++;
        }
        if (q.empty()) {
            continue;
        }
        else {
            sum = sum + q.top();
            q.pop();
        }
        
    }   
    cout << sum << endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明里灰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值