做项目的最大收益问题
题目描述
给定两个整数W和K,W代表你拥有的初始资金,K代表你最多可以做K个项目。再给定两个长度为N的正数数组costs[]和profits[],代表一共有N个项目,costs[i]和profits[i]分别表示第i号项目的启动资金与做完后的利润(注意是利润,如果一个项目的启动资金为10,利润为4,代表该项目最终的收入为14)。你不能并行只能串行地做项目,并且手里拥有的资金大于或等于某个项目的启动资金时,你才能做这个项目。该如何选择做项目,能让你最终的收益最大?返回最后能获得的最大资金
[要求]
时间复杂度为 O ( k log n ) O(k \log n) O(klogn),空间复杂度为 O ( n ) O(n) O(n)
输入描述:
第一行三个整数N, W, K。表示总的项目数量,初始资金,最多可以做的项目数量
第二行有N个正整数,表示costs数组
第三行有N个正整数,表示profits数组
输出描述:
输出一个整数,表示能获得的最大资金
示例1
输入
4 3 2
5 4 1 2
3 5 3 2
输出
11
说明
初始资金为3,最多做两个项目,每个项目的启动资金与利润见costs和profits。最优选择为:先做2号项目,做完之后资金增长到6,。然后做1号项目,做完之后资金增长到11。其他的任何选择都不会比这种选择好,所以返回11
备注:
1
⩽
K
⩽
N
⩽
1
0
5
1 \leqslant K \leqslant N \leqslant 10^5
1⩽K⩽N⩽105
1
⩽
W
,
c
o
s
t
s
[
i
]
,
p
r
o
f
i
t
s
[
i
]
⩽
1
0
9
1 \leqslant W, costs[i], profits[i] \leqslant 10^9
1⩽W,costs[i],profits[i]⩽109
题解:
构建两个堆,一个大跟堆,一个小根堆。对 cost 构建小根堆,把可做项目的收益放到大根堆,然后从大根堆中取出元素累加,再从小根堆中寻找可以做的项目,最多循环K次或没有可做项目则停止。
代码:
#include <cstdio>
#include <queue>
using namespace std;
const int N = 100000;
typedef pair<int, int> PII;
struct cmp {
bool operator() ( const PII& p1, const PII& p2 ) const {
return p1.first > p2.first;
}
};
int profit[N];
int n, w, k;
priority_queue< PII, vector<PII>, cmp > p1;
priority_queue<int> p2;
int main( void ) {
scanf("%d%d%d", &n, &w, &k);
for ( int i = 0; i < n; ++i ) {
int c;
scanf("%d", &c);
p1.push( {c, i} );
}
for ( int i = 0; i < n; ++i ) scanf("%d", profit + i);
long long ret = w;
while ( k -- ) {
while ( p1.size() && p1.top().first <= ret ) {
p2.push(profit[ p1.top().second ]);
p1.pop();
}
if ( p2.empty() ) break;
ret += p2.top();
p2.pop();
}
return 0 * printf("%lld\n", ret);
}