DP11 高楼扔鸡蛋问题 Egg Dropping Puzzle @geeksforgeeks

 

100层楼,两个鸡蛋。某层之上扔鸡蛋就会碎。问至少要测试多少次才能找出这层楼来?


思路:
首先要理解清楚题意,本题不是要找在哪一层以上会把鸡蛋扔破!而是我们假设在W层以上会把鸡蛋仍破,现在问至少要测试Y次才能找到这个W层?求的是Y
另外一个要注意的是本题中要基于扔的人运气最差的情况,即要保证在worst case下也能找到。
定义W层位蛋破层,则
我们第一次从第x层扔蛋下去,有两种可能:
1) 蛋破了:这说明了两点 1.我们手上仍然有n-1颗蛋 2.蛋破层一定在1...x-1之间,这里共有x-1-1+1 =>x-1数量的嫌疑楼层
2)蛋没破:这也说明了两点 1.我们手上仍然有n颗蛋 2.蛋破层一定在x+1...k之间,这里共有k-(x+1)+1 =>k-x数量的嫌疑楼层

定义eggDrop(n, k)为在最差情况下找出蛋破层所需要的最少扔数。n为蛋的数量,k为要检查的连续的楼层的数量
因为我们要基于最差情况,所以我们要选择两种可能之间更坏的那种,即导致扔的数量更多的那种情况,
max(eggDrop(n - 1, x - 1), eggDrop(n, k - x))
然后我们遍历所有楼层,要找出能使得最后扔的数量最小的那个初始楼层,因此
eggDrop(n, k) = 1 + min{max(eggDrop(n - 1, x - 1), eggDrop(n, k - x)): x in {1, 2, ..., k}}
加1是因为在第x层测试时也消耗了1次。

 

package DP;

/**
 * 100层楼,两个鸡蛋。某层之上扔鸡蛋就会碎。问至少要测试多少次才能找出这层楼来
 * 我们可以决定怎么扔(min),但必须假设我们的运气最差(max)
 */
public class EggDroppingPuzzle {

	public static void main(String[] args) {
		int n = 2, k = 20;
		System.out.println(eggDropDP(n, k));
		System.out.println(eggDropRec(n, k));
	}
	
	/* Function to get minimum number of trails needed in worst
	  case with n eggs and k floors */
	// n: 手上完好蛋的数量
	// k: 要测试的连续楼层的数量
	public static int eggDropRec(int n, int k){
		// If there are no floors, then no trials needed. OR if there is
	    // one floor, one trial needed.
		if(k==1 || k==0){
			return k;
		}
		// We need k trials for one egg and k floors
		if(n == 1){
			return k;
		}
		int min = Integer.MAX_VALUE;
		
		/**
		 我们要决策怎么扔使得总扔数最少(即使在我们运气最差的情况下)worst-case
		 所以在每一楼都测试第一扔,然后递归计算出总共需要的扔数,找到扔数最小的数量
		 所以假设在第x层扔第一个蛋:
		 结果1:蛋破了->现在我们只有n-1个蛋,还要测试x-1数量的楼层[1,x-1] -> 数量=x-1 -1 + 1 = x-1
		 结果2: 但没破 -> 现在我们仍有n个蛋,还要测试k-x数量的楼层[x+1,k] -> 数量=k - (x+1) + 1 = k-x
		 */
		for(int x=1; x<=k; x++){
			int res = Math.max(eggDropRec(n-1, x-1), eggDropRec(n, k-x));
			min = Math.min(min, res);
		}
		return min+1;		// +1是因为测试当前层消耗了一次扔
	}

	/* Function to get minimum number of trails needed in worst
	  case with n eggs and k floors */
	// Time Complexity: O(nk^2), Auxiliary Space: O(nk)
	public static int eggDropDP(int n, int k){
		/* A 2D table where entery dp[i][j] will represent minimum
	       number of trials needed for i eggs and j floors. */
		int[][] dp = new int[n+1][k+1];	
		
		// We need one trial for one floor and0 trials for 0 floors
		for(int i=1; i<=n; i++){
			dp[i][1] = 1;
			dp[i][0] = 0;
		}
		// We always need j trials for one egg and j floors.
		for(int j=1; j<=k; j++){
			dp[1][j] = j;
		}
		// Fill rest of the entries in table using optimal substructure
	    // property
		for(int i=2; i<=n; i++){			// i eggs
			for(int j=2; j<=k; j++){	// j floors
				dp[i][j] = Integer.MAX_VALUE;
				for(int x=1; x<=j; x++){	// try every floor from 1...j
					int res = 1 + Math.max(dp[i-1][x-1], dp[i][j-x]);
					dp[i][j] = Math.min(dp[i][j], res);
				}
			}
		}
		return dp[n][k];
	}
}

  

posted @ 2013-12-26 02:35  WingWing111  阅读(948)  评论(0编辑  收藏  举报