K - Summer Vacation

【题目描述】

有一次性的工作可用。如果您接受第 -份工作并完成它,您将从您完成工作的那天起获得几天后的奖励。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
#include
#include
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 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;
}

你可能感兴趣的:(题组,算法,c++,开发语言,学习,思维)