首页 > 试题广场 >

做项目的最大收益问题

[编程题]做项目的最大收益问题
  • 热度指数:3016 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定两个整数W和K,W代表你拥有的初始资金,K代表你最多可以做K个项目。再给定两个长度为N的正数数组costs[]和profits[],代表一共有N个项目,costs[i]和profits[i]分别表示第i号项目的启动资金与做完后的利润(注意是利润,如果一个项目的启动资金为10,利润为4,代表该项目最终的收入为14)。你不能并行只能串行地做项目,并且手里拥有的资金大于或等于某个项目的启动资金时,你才能做这个项目。该如何选择做项目,能让你最终的收益最大?返回最后能获得的最大资金
[要求]
时间复杂度为,空间复杂度为

输入描述:
第一行三个整数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 

备注:

贪心算法,按照成本先将所有项目升序排列,然后把能做的项目拿出来按照利润降序排列,选择利润最大的做,周而复始直到无项目可做。用一个大根堆和一个小根堆来完成排序操作。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.PriorityQueue;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] params = br.readLine().split(" ");
        PriorityQueue<int[]> minHeap = new PriorityQueue<>((program1, program2) -> program1[0] - program2[0]);
        PriorityQueue<int[]> maxHeap = new PriorityQueue<>((program1, program2) -> program2[1] - program1[1]);
        int n = Integer.parseInt(params[0]), k = Integer.parseInt(params[2]);
        long w = Long.parseLong(params[1]);
        int[][] programs = new int[n][2];
        params = br.readLine().split(" ");
        for(int i = 0; i < n; i++) programs[i][0] = Integer.parseInt(params[i]);
        params = br.readLine().split(" ");
        for(int i = 0; i < n; i++) {
            programs[i][1] = Integer.parseInt(params[i]);
            minHeap.offer(programs[i]);
        }
        // 只能做k个项目
        for(int i = 0; i < k; i++){
            while(!minHeap.isEmpty() && w >= minHeap.peek()[0]){
                // 可以做的项目放入大根堆
                maxHeap.offer(minHeap.poll());
            }
            if(maxHeap.isEmpty())
                break;                       // 没有可以做的项目了
            else
                w += maxHeap.poll()[1];      // 可以做的项目选利润最大的
        }
        System.out.println(w);
    }
}

发表于 2021-11-13 15:53:05 回复(0)
这题时间复杂度的要求应该是O(nlogn)。可维护最小花费堆minCostHeap和最大利益堆maxProfitHeap,将所有花费不超过现有资金的项目从minCostHeap移至maxProfitHeap,从maxProfitHeap中取出堆顶项目做。
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int w = sc.nextInt();
        int k = sc.nextInt();
        int[] costs = new int[n];
        int[] profits = new int[n];
        for (int i = 0; i < n; ++i) {
            costs[i] = sc.nextInt();
        }
        for(int i = 0; i < n; ++i) {
            profits[i] = sc.nextInt();
        }

        System.out.println(getMaxMoney(costs, profits, k, w));
    }

    private static long getMaxMoney(int[] costs, int[] profits, int k, long w) {
        if (k < 1 || costs.length != profits.length) {
            return 0;
        }
        PriorityQueue<Project> minCostQue = new PriorityQueue<>((Comparator.comparingInt(o -> o.cost)));
        PriorityQueue<Project> maxProfitQue = new PriorityQueue<>(((o1, o2) -> o2.profit - o1.profit));
        for (int i= 0; i < costs.length; ++i) {
            minCostQue.add(new Project(costs[i], profits[i]));
        }
        while(k-- > 0) {
            while (!minCostQue.isEmpty() && minCostQue.peek().cost <= w) {
                maxProfitQue.add(minCostQue.remove());
            }
            if (maxProfitQue.isEmpty()) {
                break;
            }
            w += maxProfitQue.remove().profit;
        }
        return w;
    }

    static class Project {
        int cost;
        int profit;

        public Project(int cost, int profit) {
            this.cost = cost;
            this.profit = profit;
        }
    }
}


发表于 2021-09-02 09:40:25 回复(1)
#include <bits/stdc++.h>
using namespace std;

struct P{
    int cost, w;
};

bool cmp(P a, P b){
    return a.cost < b.cost;
}

int main(){
    long n,w,k;
    cin>>n>>w>>k;
    P v[n];
    for(int i=0;i<n;i++)
        cin>>v[i].cost;
    for(int i=0;i<n;i++)
        cin>>v[i].w;
    sort(v, v+n, cmp);
    priority_queue<int> q;
    for(int i=0;i<n && k;i++){
        for(;k && v[i].cost>w;k--){
            if(q.empty()){
                cout<<w<<endl;
                return 0;
            }
            w += q.top();
            q.pop();
        }
        q.push(v[i].w);
    }
    for(;k && !q.empty();k--){
        w += q.top();
        q.pop();
    }
    cout<<w<<endl;
    return 0;
}

发表于 2020-03-18 00:03:55 回复(0)
#include<iostream>
#include<vector>
#include<queue>

using namespace std;

class Project{
public:
    Project(long x, long y)
    {
        cost = x;
        profit = y;
    }
    long cost;
    long profit;
};

struct minCostCmp{
    bool operator()(Project* p1, Project* p2)
    {
        return p1->cost > p2->cost; // 小根堆
    }
};
struct maxProfitCmp{
    bool operator()(Project* p1, Project* p2)
    {
        return p1->profit < p2->profit; // 大根堆
    }
};

int main()
{
    int n, k;
    long w;
    cin >> n >> w >> k;
    vector<long> costs(n, 0);
    for (int i=0; i<n; i++) cin >> costs[i];
    vector<long> profits(n, 0);
    for (int i=0; i<n; i++) cin >> profits[i];
    vector<Project*> projects(n, NULL);
    for (int i=0; i<n; i++)
    {
        projects[i] = new Project(costs[i], profits[i]);
    }
    priority_queue<Project*, vector<Project*>, minCostCmp> minCostHeap;
    priority_queue<Project*, vector<Project*>, maxProfitCmp> maxProfitHeap;
    for (int i=0; i<n; i++) minCostHeap.push(projects[i]);
    for (int i=0; i<k; i++)
    {
        while (!minCostHeap.empty() && minCostHeap.top()->cost <= w)
        {
            maxProfitHeap.push(minCostHeap.top());
            minCostHeap.pop();
        }
        if (maxProfitHeap.empty()) cout << w << endl;
        w += maxProfitHeap.top()->profit;
        maxProfitHeap.pop();
    }
    cout << w << endl;
    return 0;
}

发表于 2019-10-15 12:00:37 回复(0)

来个Python3版本的

N, W, K = (int(_) for _ in input().strip().split())
if N <=0:
    print(W)
costs = [int(_) for _ in input().strip().split()]
profits = [int(_) for _ in input().strip().split()]
items = [(a, b) for a, b in zip(costs, profits)]
import heapq
heapq.heapify(items)  # 先把所有项目按照花费的小根堆组织起来
more_q = []  # 大根堆按照profits组织
# 循环 K 次选择 K 个项目
for i in range(K):
    # 把当前资金能做的项目从小根堆中弹出,并进入大根堆
    while len(items)>0 and items[0][0] <= W:
        one_item = heapq.heappop(items)
        heapq.heappush(
            more_q, (-one_item[1],) + one_item
        )  # 由于默认小根堆,所以把利润取反后push进小根堆,就是大根堆了
    # 循环结束时, one_item 是当前轮初始资金不能做的
    if len(more_q) == 0: # 如果大根堆没有元素了,代表当前的资金无法做任何项目了,可以提前停止了
        break

    # 从大根堆中取出一个项目做,并把收益加到资金中
    do_item = heapq.heappop(more_q)[1:]
    W +=  do_item[1]
print(W)
发表于 2023-03-15 22:17:42 回复(0)
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

struct Node{
    int cost;
    int profit;
};

struct greaterCost{
    bool operator () (const Node& n1, const Node &n2) const{
        return n1.cost > n2.cost;
    }
};

struct lessProfit{
    bool operator () (const Node& n1, const Node& n2) const{
        return n1.profit < n2.profit;
    }
};

long getW(const vector<Node> &v, long W, int K){
    priority_queue<Node, vector<Node>, greaterCost> pCost;
    priority_queue<Node, vector<Node>, lessProfit> pProfit;
    for(int i = 0; i < v.size(); i++){
        pCost.emplace(v[i]);
    }
    for(int i = 0; i < K; i++){
        while(!pCost.empty() && W >= pCost.top().cost){
            pProfit.emplace(pCost.top());
            pCost.pop();
        }
        if(pProfit.empty()){
            return W;
        }
        W += pProfit.top().profit;
        pProfit.pop();
    }
    return W;
}

int main(void){
    int N, K;
    long W;
    cin >> N >> W >> K;
    vector<Node> v(N);
    for(int i = 0; i < N; i++){
        cin >> v[i].cost;
    }
    for(int i = 0; i < N; i++){
        cin >> v[i].profit;
    }
    cout << getW(v, W, K) << endl;
    return 0;
}
使用两个优先队列来做
在处理K的时候本人出现问题,后解决
而且这个问题不加上启动资金,只加上利润
发表于 2021-05-23 09:06:28 回复(0)
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int w = scanner.nextInt();
        int k = scanner.nextInt();
        scanner.nextLine();
        int[] casts = new int[n];
        int[] profits = new int[n];
        for (int i = 0; i < n; i++) {
            casts[i] = scanner.nextInt();
        }
        scanner.nextLine();
        for (int i = 0; i < n; i++) {
            profits[i] = scanner.nextInt();
        }
        long maxGains = getMaxGains(casts, profits, k, w);
        System.out.println(maxGains);
    }

    /**
     * @param casts   项目所需花费
     * @param profits 项目利润
     * @param k       可做项目个数
     * @param w       初始资金
     * @return
     */
    public static long getMaxGains(int[] casts, int[] profits, int k, int w) {
        long maxResult = w;
        //堆中存放索引,在数组中查找对应的利润和成本,可以把两个数组串联起来省去创建对象,优雅!
        PriorityQueue<Integer> minHeap = new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                //小根堆,根据casts数组
                return casts[o1] - casts[o2];
            }
        });
        PriorityQueue<Integer> maxHeap = new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                //大根堆,根据profits数组
                return profits[o2] - profits[o1];
            }
        });
        for (int i = 0; i < casts.length; i++) {
            minHeap.offer(i);
        }
        //当堆不为空且堆顶元素花费小于等于成本时,把他转到利润堆中
        while (!minHeap.isEmpty() && casts[minHeap.peek()] <= w) {
            maxHeap.offer(minHeap.poll());
        }
        for (int i = 0; i < k; i++) {
            int profit = profits[maxHeap.poll()];
            maxResult += profit;
            w += profit;
            //更新堆
            while (!minHeap.isEmpty() && casts[minHeap.peek()] <= w) {
                maxHeap.offer(minHeap.poll());
            }
        }
        return maxResult;
    }
}
引入两个堆,一个最小堆,一个最大堆,对costs构造最小堆,把可以做的项目按照项目收益放到最大堆,在最大堆取出堆顶元素,累加,再在最小堆中找到可以做的项目加到最大堆,循环k次


编辑于 2020-03-13 22:24:55 回复(0)
#include <iostream>
#include <vector>
#include <queue>

using namespace std;
using Node = pair<long, long>;

int main(void) 
{
    long N, W, K;
    cin >> N >> W >> K;
    long *costs = new long[N];
    long *profits = new long[N];
    for (int i = 0; i < N; i++)
        cin >> costs[i];
    for (int i = 0; i < N; i++)
        cin >> profits[i];
    
    auto cmp1 = [](Node &a, Node &b){return a.first > b.first;};
    auto cmp2 = [](Node &a, Node &b){return a.second < b.second;};
    priority_queue<Node, vector<Node>, decltype(cmp1)> min_heap(cmp1);
    priority_queue<Node, vector<Node>, decltype(cmp2)> max_heap(cmp2);
    for (int i = 0; i < N; i++)
        min_heap.push({costs[i], profits[i]});
    
    while (K--) {
        while (!min_heap.empty() && min_heap.top().first <= W) {
            max_heap.push(min_heap.top());
            min_heap.pop();
        }
        if (max_heap.empty()) break;
        W += max_heap.top().second;
        max_heap.pop();
    }
    cout << W << endl;
}

发表于 2020-02-13 16:17:16 回复(0)
#include<bits/stdc++.h>
using namespace std;
struct Project{
    int cost;
    int profit;
    Project(int a,int b):cost(a),profit(b){}
};
struct cmp1{
    bool operator()(Project p,Project q)
    {
        return p.cost>q.cost;
    }
};
struct cmp2{
    bool operator()(Project p,Project q)
    {
        return p.profit<q.profit;
    }
};
int main()
{
    int N,K;
    long W;
    cin>>N>>W>>K;
    // 最小花费 小顶堆
    priority_queue<Project,vector<Project>,cmp1>pq_costMin;
    // 最大利润 大顶堆
    priority_queue<Project,vector<Project>,cmp2>pq_ProfitMax;
    vector<int>cost(N,0);
    vector<int>profit(N,0);
    for(int i=0;i<N;++i)
        cin>>cost[i];
    for(int i=0;i<N;++i)
        cin>>profit[i];
    for(int i=0;i<N;++i)
         pq_costMin.push(Project(cost[i],profit[i]));
    while(!pq_costMin.empty() && pq_costMin.top().cost<=W)
    {
        pq_ProfitMax.push(pq_costMin.top());
        pq_costMin.pop();
    }
    while(K>0 && !pq_ProfitMax.empty())
    {
        Project cur = pq_ProfitMax.top();
        pq_ProfitMax.pop();
        W += cur.profit;
        --K;
        while(!pq_costMin.empty() && pq_costMin.top().cost<=W)
        {
            pq_ProfitMax.push(pq_costMin.top());
            pq_costMin.pop();
        }

    }
    cout<<W;
    return 0;
}
发表于 2020-02-11 22:39:50 回复(0)
#include <bits/stdc++.h>
using namespace std;

struct Node{
    int profit;
    int cost;
};
struct tmp1{
    bool operator() (Node a, Node b){
        return a.profit < b.profit; //大顶堆
    }
};
struct tmp2{
    bool operator() (Node a, Node b){
        return a.cost > b.cost; //小顶堆
    }
};

int main(){
    long n, money, k;
    cin >> n >> money >> k;
    vector<Node> pj(n);
    for(int i = 0;i<n;i++) cin >> pj[i].cost;
    for(int i = 0;i<n;i++) cin >> pj[i].profit;

    priority_queue<Node, vector<Node>, tmp1> maxPHeap;
    priority_queue<Node, vector<Node>, tmp2> minCHeap;
    for(int i=0; i<n; i++){
        minCHeap.push(pj[i]);
    }
    for(int i=0; i<k; i++){
        while(minCHeap.top().cost <= money && !minCHeap.empty()){
            maxPHeap.push(minCHeap.top()); minCHeap.pop();
        }
        if(!maxPHeap.empty()){
            int get = maxPHeap.top().profit; maxPHeap.pop();
            money += get;
        } else break;
    }
    cout << money;
    return 0;
}

编辑于 2020-02-07 22:21:57 回复(1)

import java.io.*;
import java.util.*;
public class Main{
    static int [] c ;
    static int [] p ;
    public static void main(String[] args)throws IOException{
        BufferedReader b = new BufferedReader(new InputStreamReader(System.in));
        String [] a = b.readLine().trim().split(" ");
        int n = Integer.parseInt(a[0]);
        int w = Integer.parseInt(a[1]);
        int k = Integer.parseInt(a[2]);
         
        c = new int[n];
        p = new int[n];
        String [] aa = b.readLine().trim().split(" ");
        String [] aaa = b.readLine().trim().split(" ");
        for(int i = 0;i < n; i++){
            c[i] = Integer.parseInt(aa[i]);
            p[i] = Integer.parseInt(aaa[i]);
        }
        b.close();
         
         
         // 核心代码,队列里面放的是表示项目的索引,这样不用创建新的对象
        PriorityQueue<Integer> maxH = new PriorityQueue<>((o1, o2) -> (p[o2] - p[o1])); //大根堆,项目启动金额<=w的加入maxH,按照利润来排序。
        PriorityQueue<Integer> minH = new PriorityQueue<>((o1, o2) -> (c[o1] - c[o2])); //小根堆,项目启动金额>w的加入小根堆,按照启动金额大小排序
         
        for(int i = 0; i < n; i++){
            if(c[i] > w){
                minH.add(i);
            }else{
                maxH.add(i);
            }
        }
        //每一次都将小根堆中启动金额小于w的取出放入到大根堆中,跟新w
        while(k != 0 && !maxH.isEmpty()){
            while(!minH.isEmpty()&& c[minH.peek()] <= w){
                maxH.offer(minH.poll());
            }
            w += p[maxH.poll()];//有个测试用例w超过int上限
            k--;
        }
        System.out.println(w);
    }
}
编辑于 2020-03-20 10:38:29 回复(2)