1. 程式人生 > 其它 >雞蛋掉落

雞蛋掉落

給你 k 枚相同的雞蛋,並可以使用一棟從第 1 層到第 n 層共有 n 層樓的建築。

已知存在樓層 f ,滿足0 <= f <= n ,任何從 高於 f 的樓層落下的雞蛋都會碎,從 f 樓層或比它低的樓層落下的雞蛋都不會破。

每次操作,你可以取一枚沒有碎的雞蛋並把它從任一樓層 x 扔下(滿足1 <= x <= n)。如果雞蛋碎了,你就不能再次使用它。如果某枚雞蛋扔下後沒有摔碎,則可以在之後的操作中 重複使用 這枚雞蛋。

請你計算並返回要確定 f 確切的值 的 最小操作次數 是多少?

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/super-egg-drop


著作權歸領釦網路所有。商業轉載請聯絡官方授權,非商業轉載請註明出處。

import java.util.Scanner;

class Solution {

    public static int superEggDrop1(int K, int N) {

        int v = log2N(N) + 1;
        if (K >= v) {
            return v;
        }

        int[][] dp = new int[N + 1][K + 1];

        for (int i = 1; i <= N; ++i) {
            dp[i][1] = i;
        }

        for (int i = 1; i <= K; ++i) {
            dp[1][i] = 1;
        }

        for (int i = 2; i <= N; ++i) {

            for (int j = K; j >= 2; --j) {
                dp[i][j] = Integer.MAX_VALUE;

                for (int k = 1; k <= i; ++k) {
                    if (dp[i][j] > Math.max(dp[i - k][j], dp[k - 1][j - 1]) + 1) {
                        dp[i][j] = Math.max(dp[i - k][j], dp[k - 1][j - 1]) + 1;
                    }
                }
            }
        }
        return dp[N][K];
    }

    public static int superEggDrop2(int K, int N) {

        int v = (int) (Math.log(N) / Math.log(2)) + 1;
        if (K >= v) {
            return v;
        }

        int[][] dp = new int[N + 1][K + 1];
        int[][] choose = new int[N + 1][K + 1];

        for (int i = 1; i <= N; ++i) {
            dp[i][1] = i;
            choose[i][1] = 1;
        }

        for (int i = 1; i <= K; ++i) {
            dp[1][i] = 1;
            choose[1][i] = 1;
        }

        for (int i = 2; i <= N; ++i) {
            for (int j = K; j >= 2; --j) {
                dp[i][j] = Integer.MAX_VALUE;
                int down = Math.max(1, choose[i - 1][j]);
                int up = Math.min(j == K ? i : choose[i][j + 1], i);
                for (int k = down; k <= up; k++) {
                    /**
                     * 要更新右側格子,所以等於
                     */
                    if (dp[i][j] >= Math.max(dp[k - 1][j - 1], dp[i - k][j]) + 1) {
                        dp[i][j] = Math.max(dp[k - 1][j - 1], dp[i - k][j]) + 1;
                        choose[i][j] = k;
                    }
                }
            }
        }
        return dp[N][K];
    }

    /**
     * dp[i][j]
     * dp[0][j] = 0
     * dp[i][0] = 0
     * i 個蛋,扔 j 次達到的最大高度
     *
     * @return
     */
    public static int superEggDrop(int K, int N) {

        int v = (int) (Math.log(N) / Math.log(2)) + 1;
        if (K >= v) {
            return v;
        }

        int[] dp = new int[K + 1];

        int ret = 0;

        while (true) {

            ret++;

            /**
             * dp[i][j] = dp[i][j - 1] + 1 + dp[i - 1][j - 1]
             *
             * 假設扔到最優位置
             *
             * 1. 沒碎
             * dp[i][j - 1]
             *
             * 2. 碎了
             * dp[i - 1][j - 1]
             *
             */
            int previous = 0, tmp;
            for (int i = 1; i <= K; ++i) {
                tmp = dp[i];
                dp[i] = dp[i] + previous + 1;
                previous = tmp;
                if (dp[i] >= N) {
                    return ret;
                }
            }
        }
    }

    public static int log2N(int n) {
        int res = -1;
        while (n != 0) {
            res++;
            n >>>= 1;
        }
        return res;
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (in.hasNext()) {
            System.out.println(superEggDrop(in.nextInt(), in.nextInt()));
        }
    }
}
心之所向,素履以往 生如逆旅,一葦以航