1. 程式人生 > >Coursera Algorithms week1 練習測驗:Egg drop 扔雞蛋問題

Coursera Algorithms week1 練習測驗:Egg drop 扔雞蛋問題

轉自 https://www.cnblogs.com/evasean/p/7208986.html

題目原文:

Suppose that you have an n-story building (with floors 1 through n) and plenty of eggs. An egg breaks if it is dropped from floor T or higher and does not break otherwise. Your goal is to devise a strategy to determine the value of T given the following limitations on the number of eggs and tosses:

Version 0: 1 egg, ≤T tosses.
Version 1: ∼1lgn eggs and ∼1lgn tosses.
Version 2: ∼lgT eggs and ∼2lgT tosses.
Version 3: 2 eggs and ∼2 n \sqrt{n} tosses.
Version 4: 2 eggs and ≤c T

\sqrt{T} tosses for some fixed constant c
分析:

version0 : 拿著一個雞蛋從1~n依次扔就可以,到floor T會碎,故複雜度為≤T

version 1: 採用二分查詢,首先從n/2層開始扔:

if(雞蛋碎) 從(n/2)/2層開始扔;

else 從n/2+(n/2)/2層開始扔

二分方法需要lgn個雞蛋嘗試lgn次

version 2: 依次從1, 2, 4, 8, 16, 32,…2k開始扔,如果雞蛋在2k

碎了,那麼2k-1≤T≤2k,這時已經使用了 lgT 次步,接下來在[2k-1+1,2k)區間進行version1的二分查詢方法,需要花費lgT步。這兩種操作加起來總共花費2lgT步

version 3: 將0~n層樓分成[1, n \sqrt{n} -1], [ n \sqrt{n} , 2 n \sqrt{n} -1], [2 n \sqrt{n} ,3 n \sqrt{n} -1]…[k n \sqrt{n} , (k+1) n \sqrt{n} -1]…個區間,用一個雞蛋分佈從1開始在各個區間的起始樓層扔,如果在k n \sqrt{n} 層碎了,那就從(k-1) n \sqrt{n} +1開始逐層扔。第一步區間選擇用了 n \sqrt{n} 的複雜度,第二步區間內部扔雞蛋用了 n \sqrt{n} 的複雜度,總共用了2 n \sqrt{n}

version 4: 嘗試從1, 4, 9, 16, 25,…(k-1)2, k2…樓層扔雞蛋,加入雞蛋在樓層k2碎了,意味著(k-1)2≤T≤k2,這一步嘗試了 T \sqrt{T} 次(k= T \sqrt{T} )。接著從樓層(k-1)2+1開始逐層扔,最多嘗試至k2-1結束,這一步需要嘗試k2-1-(k-1)2-1=2 T \sqrt{T} -1=2 T \sqrt{T} -2次。總共用了3 T \sqrt{T} -2次

程式碼實現

package eggdrop;

public class EggDrop {
	//供預測的提前設定的解,也可以直接random一個,為方便測試直接給定。
    public static int T = 10;
    //嘗試了幾次
    static int numsOfTry = 0;
    //摔碎了多少個雞蛋
    static int numsOfEggBroken = 0;
    //扔雞蛋抽象為一個方法,扔的時候更新嘗試次數和雞蛋碎了沒有的次數,同時列印嘗試的過程和結果
    public static boolean drop(int i){
        numsOfTry++;
        if(i < T) {
            System.out.println("from " + i + " no");
            return false;
        }
        else{
            System.out.println("from " + i + " yes");
            numsOfEggBroken++;
            return true;
        }
    }
    //以下為version0-4的實現,前面註釋給出的兩個數字分別為 
    //(摔壞的雞蛋數的期望,嘗試次數的期望)
    
    //1egg;T
    public static void go0(int n){
        for (int i = 0; i < n; i++) {
            boolean tmp = drop(i);
            if(tmp == true) {
                System.out.println("T is " + i);
                break;
            }
        }
    }
    
    //lg(n)egg;lg(n)
    //為方便go2呼叫,把其改為了帶上下界的二分的方法。
    public static void go1(int n,int start,int end){


        boolean tmp = drop((start + end) / 2);;

        while(start < end) {
            if (tmp == false) {
                start = (start + end) / 2 + 1;
                tmp = drop((start + end) / 2);
            }
            else{
                end = (start + end) / 2 - 1;
                tmp = drop((start + end) / 2);
            }
        }
        if(tmp == false){
            System.out.println("T is " + ((start + end) / 2 + 1));
        }else{
            System.out.println("T is " + (start + end) / 2);
        }
    }
    
    //lg(T)egg;2lg(T)
    public static void go2(int n){
        int k = -1;
        int start = 0;
        int end = n - 1;
        for (int i = 0; i < Math.sqrt(n) - 1; i++) {
            int t = (int)Math.pow(2,(double)i);
            boolean tmp = drop(t);
            if(tmp == true){
                k = (int)Math.pow(2,(double)i);
                start = (int)Math.pow(2,(double)i - 1);
                end =(int)Math.pow(2,(double)i);
                break;
            }

        }
        go1(n, 0 ,n - 1);
    }
    
    //2egg;2根號n
    public static void go3(int n){
        int l = (int) Math.sqrt(n);
        int k = -1;
        for (int i = 0; i * l < n; i++) {
            boolean tmp = drop(i * l);
            if(tmp == true){
                k = i;
                break;
            }
        }
        for (int i = (k-1) * l + 1; i < k * l; i++) {
            boolean tmp = drop(i);
            if(tmp == true){
                System.out.println("\nT is " + i);
            break;
            }
        }
    }
    
    //2egg ;3根號T
    public static void go4(int n){
        int k = -1;
        for (int i = 0; Math.pow(i, 2) < n; i++) {
            boolean tmp = drop((int)Math.pow(i, 2));
            if(tmp == true){
                k = i;
                break;
            }
        }
        for (int i = (int)Math.pow(k-1, 2) + 1; i < Math.pow(k, 2); i++) {
            boolean tmp = drop(i);
            if(tmp == true){
                System.out.println("\nT is " + i);
                break;
            }
        }
    }


    public static void main(String[] args) {
        int n = 40;
        //方便go2呼叫
        //go1(n,0, n-1);
        go4(n);
        System.out.println("Number of the Broken Eggs  is " + numsOfEggBroken);
        System.out.println("Number of trying is " + numsOfTry);
    }
}