算法学习|贪心法

贪心法是一种解决最优化问题的方法,通过每次选取局部最优解逐步达到全局最优。例如在月饼销售问题中,选取单价最高的月饼销售以获得最大收益;在哈夫曼树构建中,通过优先队列求最小加权路径;区间类问题中,寻找线段覆盖率最大或线段最多的策略。这些例子展示了贪心算法在不同场景下的应用。
摘要由CSDN通过智能技术生成

贪心法

贪心法是一类求取最优化问题的办法,贪心法在遵循某种规则的情况下对当前状态进行判断,每次在进行状态转换的情况时选取其中能使当前状况获得最大收益的办法(当前状况下的局部最优),最终通过局部最优来取得全局最优解的办法。

以下列出几个例子,演示贪心法通常的应用情况:

  1. (1020 月饼 (25分) ----- 求解最大收益类问题

月饼是中国人在中秋佳节时吃的一种传统食品,不同地区有许多不同风味的月饼。现给定所有种类月饼的库存量、总售价、以及市场的最大需求量,请你计算可以获得的最大收益是多少。

注意:销售时允许取出一部分库存。样例给出的情形是这样的:假如我们有 3 种月饼,其库存量分别为 18、15、10 万吨,总售价分别为 75、72、45 亿元。如果市场的最大需求量只有 20 万吨,那么我们最大收益策略应该是卖出全部 15 万吨第 2 种月饼、以及 5 万吨第 3 种月饼,获得 72 + 45/2 = 94.5(亿元)。

根据题意可以知道贪心法在此问题中遵循的规则是 使得销售获取的收益最大,进一步说就是每次选取时都选取单价售出价格最高的物品

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.Arrays;
import java.util.Comparator;

class pair {
	public double w; // 重量
	public double v; // 价格
	public double uintV;
}

public class Main {
	public static void main(String[] args) throws IOException {
		// 数据输入模块
		int n, W;
		 StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
		in.nextToken();
		n = (int)in.nval;
		in.nextToken();
		W = (int)in.nval;
		pair[] data = new pair[n];
		for (int i = 0; i < n; i++) {
			data[i] = new pair();
			in.nextToken();
			data[i].w = in.nval;
		}
		for(int i = 0;i < n;i++) {
			in.nextToken();
			data[i].v = in.nval;
			data[i].uintV = data[i].v / data[i].w;
		}

		// 数据预处理
		
		  Arrays.sort(data, new comparator()); 
		  double Sum = 0; 
		  
		  // 计算当前最大收益
		  for(int i = 0;i < n && W> 0;i++) { 
			  double temp = Math.min(W, data[i].w); 
			  W -= temp; 
			  Sum +=data[i].uintV * temp; 
			}
		  
		  System.out.printf("%.2f",Sum);
		 
	}
}
class comparator implements Comparator<pair> {
	@Override
	public int compare(pair o1, pair o2) {
		// TODO Auto-generated method stub
		if(o1.uintV - o2.uintV > 0) {
			return -1;
		} else {
			return 1;
		}
	}
}

该类问题通常都有很明确的划分点,可以保证下一步状态转换是局部最优的。

2.哈夫曼树 ----- 俩俩合并类问题/合并果子问题  例题为Poj-3253

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.PriorityQueue;
import java.util.Queue;

public class Main {
	public static void main(String[] args) throws IOException {
		StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
		in.nextToken();
		int n = (int)in.nval;
		Queue<Integer> queue = new PriorityQueue<Integer>(); 
		// 数据预处理
		for(int i = 0;i < n;i++) {
			in.nextToken();
			int temp = (int)in.nval;
			queue.offer(temp);
		}
		
		// 求最小加权路径
		long ans = 0;
		while(queue.size() != 1) {
			Integer a = queue.poll();
			Integer b = queue.poll();
			ans += a + b;
			queue.offer(a+b);
		}
		System.out.println(ans);
	}
}

 

此类问题需要对二叉树有一定了解,本质上就是求树的最小加权路径。

  这里我们采用优先队列的数据类性进行辅助处理,可以更容易的获取解。

3 区间类问题 

 问题通常为多个线段映射到一条直线上,求解如何选择线段使得线段覆盖率最大或者线段最多问题。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值