POJ-3783 Balls

在这里插入图片描述
在这里插入图片描述

代码

import java.util.Scanner;

public class Main {
	
	private static int MAX_FLOOR = 1000 + 5;
	private static int MAX_BALL = 50 + 5;
	
	public static void main(String[] args){
		int[][] dp = new int[MAX_FLOOR][MAX_BALL];
		
		for(int i=1; i<MAX_FLOOR; i++) {
			dp[i][1] = i;
		}
		for(int i=1; i<MAX_BALL; i++) {
			dp[1][i] = 1;
			dp[2][i] = 2;
		}
		
		for(int i=2; i<MAX_BALL; i++) {
			for(int j=3; j<MAX_FLOOR; j++) {
				int min = Integer.MAX_VALUE;
				for(int k=2; k<j; k++) {
					min = Math.min(min, Math.max(dp[k-1][i-1]+1, dp[j-k][i]+1));
				}
				dp[j][i] = min;
			}
		}
		
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		for(int i=0; i<n; i++) {
			int num = sc.nextInt();
			int B = sc.nextInt();
			int M = sc.nextInt();
			System.out.println(num + " " + dp[M][B]);
		}
		sc.close();
		
	}
}

注解

1、入门级别二维动态规划题目,这也是谷歌面试题,蓝桥杯真题(第九届C组第十题,第九届B组第四题–扔手机)
2、主要难点在于状态转移方程的推导。
核心思想:i个球,在第k层扔,状态转移成:Math.max(dp[k-1][i-1]+1, dp[j-k][i]+1)。
第一种情况:球破碎了,则转移成dp[k-1][i-1]+1,k-1表示使得球破碎的层数一定在1到k-1层的高度之间。i-1表示剩余手机数。
第二种情况:球未破碎,则转移成dp[j-k][i]+1,j-k表示使得球破碎的层数一定在k+1到j层(顶层)的高度之间。i表示剩余手机数。
3、了解了上面的核心,下面开始写动态规划的代码:首先是创建二维数组,因为是二维dp,要弄清楚每一维的含义(算法的有趣就在于,代码简短,但每个数组、下标,都是活灵活现的有实在含义的)。假设我们的数组是dp[maxfloor][maxball],第一维表示层数,第二维表示球数。好了,下面开始想想初始化:假设顶层只有一层,那么不管多少个球,只需要试一次;假设只有一个球,那么顶层是多少层,就要试多少次(从底往上一层一层试)。另外,假如顶层只有2层,那么不管多少个球,都要试2次。上面三句话就是三个初始化的代码。
4、初始化完成,下面开始动态规划了。按从简单到复杂的原则。后面要求的结果,前面一定是已经求过的(最优子结构原则)。从2个球开始(1个球的情况初始化已经完成了),从3层开始(1、2层的情况初始化已经完成了),好了,假设顶层有j层,那此时就从第2层开始,试到j-1层,一个一个试,题目要求是用最优策略的最坏情况。我们先求最坏情况吧。最坏情况就是Math.max(dp[k-1][i-1]+1, dp[j-k][i]+1),因为扔出球后,要么碎了,要么没碎,二者的最大值就是最坏情况了(运气最差的情况)。下面考虑最优策略,最优策略的意思是,此情况下,我到底该从哪一层扔,才能使得最坏情况最好呢?所以也就是

				int min = Integer.MAX_VALUE;
				for(int k=2; k<j; k++) {
					min = Math.min(min, Math.max(dp[k-1][i-1]+1, dp[j-k][i]+1));
				}

这块代码,一轮循环下来,找到一个最小值,就是最优策略。
5、竟然已经三年多没有练过POJ了,时间好快,要加油。

结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值