java数据结构和算法③——贪心和动态规划

贪心算法

概念:贪心算法又叫做贪婪算法,它在求解某个问题是,总是做出眼前最大利益。

也就是说只顾眼前不顾大局,所以它是局部最优解。

贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。

贪心算法其最重要的两个点就是:

  • 贪心策略
  • 通过局部最优解能够得到全局最优解

会议室安排问题:

有N个同等级的会议需要在同一天使用同一个会议室,现在给你这个N个会议的开始和结束时间,你怎么样才能使会议室最大利用?即安排最多场次的会议。

例如有以下时间的会议
0点~9点
8点~10点
10点~12点
8点~20点

解题思路:

优先排序
结束时间最早的会议优先,作为第一场
找剩下的结束时间最早的,而且开始时间要大于第一场结束,作为第二次
重复以上操作
class Me implements Comparable<Me> {
	private int meNum; // 会议的编号
	private int startTime; // 会议开始时间
	private int endTime; // 会议结束时间
	public Me(int meNum, int startTime, int endTime) {
		this.setMeNum(meNum);
		this.setStartTime(startTime);
		this.setEndTime(endTime);
	}
	@Override
	public int compareTo(Me o) {		//以结束时间排序 早结束的放前面
		if (this.endTime > o.endTime)
			return 1;
		return -1;
	}
	public int getMeNum() {
		return meNum;
	}
	public void setMeNum(int meNum) {
		this.meNum = meNum;
	}
	public int getStartTime() {
		return startTime;
	}
	public void setStartTime(int startTime) {
		this.startTime = startTime;
	}
	public int getEndTime() {
		return endTime;
	}
	public void setEndTime(int endTime) {
		this.endTime = endTime;
	}
	@Override
	public String toString() {
		return "Me [meNum=" + meNum + ", startTime=" + startTime + ", endTime=" + endTime + "]";
	}	
}
public class Meeting {
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		int n = cin.nextInt();	//有N个会议
		List<Me> mes = new ArrayList<>();
		for(int i = 0 ; i < n; i ++) {
			int start = cin.nextInt();
			int end = cin.nextInt();
			Me me = new Me(i+1, start, end);
			mes.add(me);
		}
		mes.sort(null);		//实现排序		这个排序其实就是 贪心的策略
		int curTime = 0 ;
		for(int i = 0;i < n; i ++) {
			Me me = mes.get(i);
			if(me.getStartTime() >= curTime) {	//判断能不能开
				System.out.println(me.toString());
				//
				curTime = me.getEndTime();
			}
		}	
	}		
}

动态规划

核心思想:分解子问题,通过局部最大值得到全局最大。

背包问题:

小偷去某商店盗窃,背有一个背包,容量是50kg,现在有以下物品(物品不能切分),请问小偷应该怎么拿才能得到最大的价值?

       重量     价值
物品1   10kg    60元   
物品2   20kg    100元 
物品3   40kg    120元  

假设有5kg的袋子
物品只有一个,且不能拆分。

钱:6  10  12
Kg:1  2   4

我们把5kg袋子拆分成1kg这样的来计算,每个格子的意思就是当前袋子在这个容量下能装的最大价值,行表示每次加的物品

添加物品1kg2kg3kg4kg5kg
加第一个物品66666
加第二个物品610161016
加第三个物品610161618

第二个进来时,如果此时袋子为2kg,我们知道在第一个物品进来时,2kg最多能装6块钱。这时候如果我们选择装第二物品那么袋子里面的钱为10块,然后剩余0kg,那么物品1就不能装了。然后发现10块大于袋子里面原来的6快,所以我们选择装第二个 丢掉第一个。

第三个物品进来,如果此时袋子为5kg,我们如果选择加第三个物品,那么袋子容积还剩1kg,能得12块,我们找到上一列1kg袋子的最大价值为6,所以总的为18。

public static void main(String[] args) {
	int value[] = {60,100,120};		//每个物品的钱
	int weight[] = {10,20,40};		//每个物品的重量 和上面的一一对应	
	int w = 50;	//袋子的容积
	int n = 3;	//物品的个数
	int dp[][] = new int[n+1][w+1];		//表示分割,成一个 小的表格
	for(int i = 1; i<=n ;i++) {		//表示物品往里面加
		for(int cw = 1; cw <= w; cw ++) {	//袋子在每一个容积下所装的最大的钱
			if(weight[i - 1] <= cw) {		//表示这个物品可以装
				dp[i][cw] = Math.max(
						value[i-1]+dp[i-1][cw-weight[i-1]],		//我装新加的物品
						dp[i-1][cw]		//我不装这个新加的这个物品
				);
			}else {
				dp[i][cw] = dp[i-1][cw];		//新加的这个装不下 ,那么就取前一个物品装值
			}
		}
	}
	System.out.println("袋子能装的最大价值:" + dp[n][w]);	
}

应用场景

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值