贪心算法--项目花费与收益问题

这篇博客讨论了一种优化策略,即在有限的资金(W)和项目数(K)下,如何选择能带来最大收益的项目。通过创建小根堆按花费排序项目,并用大根堆按收益排序可选项目,不断更新资金并选取最大收益项目,直到完成K个投资。该算法确保了在每一步都选择当前条件下收益最高的项目。

思路:将所有项目按照花费从小到大排序,选出所有的可以做的项目,然后找一个收益最大的。

现在资金增多了,继续选出所有的可以做的项目,再找一个收益最大的。直到k等于0;

实现:将输入两个数组中的每个位置的花费和收益两个值结合成一个节点。按照花费从小到大放入小根堆,如果花费小于现有资金就放入一个利益从大到小排序的大根堆中。然后从大根堆中弹出一个最大利益的值。现有资金增加,然后循环直到k等于0;

public static class Node{//项目
		int profit;
		int cost;
		public Node(int profit,int cost) {
			this.profit = profit;
			this.cost = cost;
		}
	}
	//利润比较器
	public static class ProfitComparator implements Comparator<Node>{

		@Override
		public int compare(Node o1, Node o2) {
			// TODO Auto-generated method stub
			return o2.profit - o1.profit;
		}
		
	}
	
	//花费比较器
	public static class CostComparator implements Comparator<Node>{

		@Override
		public int compare(Node o1, Node o2) {
			// TODO Auto-generated method stub
			return o1.cost - o2.cost;
		}
		
	}
	
	
	public static int findMax(int K,int W,int[] profits,int[] costs) {
		PriorityQueue<Node> minCost = new PriorityQueue<Code02_IPO.Node>(new CostComparator());
		PriorityQueue<Node> MaxProfit = new PriorityQueue<Code02_IPO.Node>(new ProfitComparator());
		
		for(int i=0;i<profits.length;i++) {//将所有的项目放到按花费排序的小根堆中
			minCost.add(new Node(profits[i],costs[i]));
		}
		for(int i=0;i<K;i++) {
			//peek表示查看小根堆中的第一个元素。并不弹出。
			while(!minCost.isEmpty()&&minCost.peek().cost<=W) {
				MaxProfit.add(minCost.poll());
			}
			//把花费小的都弹如大根堆中了,但是还是没有能做的项目就直接返回了。
			if(MaxProfit.isEmpty()) {
				return W;
			}
			W += MaxProfit.poll().profit;
			
		}
		
		
		
		return W;
	}

### 使用贪心算法解决奖学金分配问题 当处理奖学金分配问题时,可以通过分析学生当前的成绩以及所需的努力来决定哪些科目最值得投入时间复习。假设目标是最小化总复习时间的同时使平均成绩达到或超过某个阈值 `avg`。 对于给定的学生各科目的平时成绩和平常表现(例如考试前已经完成的任务分数),可以采用如下方法: #### 解决方案概述 为了最小化额外努力的时间成本,优先考虑那些能够带来最大边际收益的学科——即每单位时间内能提升最多分数的课程。这正是应用贪心策略的地方:总是挑选下一个最有价值的选择直到满足条件为止[^2]。 具体来说,在这个问题背景下,“最有价值”的定义为增加一分所需的最少小时数;因此应该先计算每一门课要提高到合格线以上所需要的额外工作量,并据此排序。 #### 实现代码 下面是一个简单的 Python 函数实现上述逻辑: ```python def min_hours_to_award_scholarship(n, avg, scores_with_effort): """ 计算获得奖学金所需的最低复习时间 参数: n (int): 科目数量 avg (float): 平均分要求 scores_with_effort (list of tuples): [(score, effort), ...], score 是原始得分, effort 表示将该科目提至满分需花费的时间. 返回: float: 达到平均分数线所需的最少复习时间 """ # 如果现有平均分已达标,则无需任何额外努力 current_avg = sum([s for s, e in scores_with_effort]) / n if current_avg >= avg: return 0.0 # 对于每一个可能的目标分数增量及其对应的成本进行评估并按性价比降序排列 value_per_hour = sorted([(e/(max_score-s), max_score-s) for s,e in scores_with_effort for max_score in range(s+1, 101)], reverse=True) total_efforts = 0.0 accumulated_improvement = 0.0 while True: improved = False for vph, improvement in value_per_hour[:]: new_total_score = sum([min(max_score, s + improvement*(vph==vp)) for vp,(s,max_score) in zip(value_per_hour, scores_with_effort)]) if new_total_score/n >= avg and not improved: total_efforts += improvement * (vph == vp) accumulated_improvement += improvement improved = True if improved or all(new_total_score/n < avg for _,(new_total_score,) in enumerate(zip((sum([min(max_score, s + improvement*(vph!=vp)) for vp,(s,max_score) in zip(value_per_hour, scores_with_effort)]))))): break return round(total_efforts, 2) # 测试案例 n = 5 avg = 85 scores_with_effort = [ (70, 10), (90, 5), (60, 20), (80, 15), (75, 12) ] print(min_hours_to_award_scholarship(n, avg, scores_with_effort)) ``` 此函数接受三个参数:科目数目 `n`, 所期望的平均分 `avg`, 和一个列表 `scores_with_effort` ,其中包含了每个学生的初始成绩和他们想要把某门功课提到最高分所需要付出的努力(以时间为单位)。它返回的是使得最终平均分不低于指定水平所必需的最少复习时间。 请注意这段代码只是一个简化版的例子用于说明概念,并未完全优化性能或考虑到所有边界情况。实际应用场景下还需要进一步完善错误处理机制和其他细节部分[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值