二分搜索-1904. 放小球

2020-06-13 18:04:45

问题描述:

n个桶中小球的个数已知,可以操作k次(每次从桶中取出一个球,或者添加一个球),每个桶有规定的最大容量W[i]。求操作后两相邻桶之间的最大差值的平方的最小值。

样例

样例 1:

输入: 
5
6
[1,2,3,4,5]
[15,15,15,15,15]
输出: 
0

说明

共有5个桶,最多操作6次,桶内的小球分别是1,2,3,4,5,桶的最大容量分别是15,15,15,15,15。

注意事项

n <= 100

W[i] <= 100

问题求解:

最大化最小的问题可以使用二分来解决。

主要问题就是check函数如何写,也就是对于最大差值mid,至少需要多少操作来完成。

dp[i][j] = 到了第i位置最大差值小于等于mid的最小操作。

    public int getAns(int n, int k, List<Integer> A, List<Integer> W) {
        int l = -1;
        int r = -1;
        for (int i = 1; i < A.size(); i++) r = Math.max(r, Math.abs(A.get(i) - A.get(i - 1)));
        while (r - l > 1) {
            int mid = l + (r - l) / 2;
            if (check(A, mid, k, W)) r = mid;
            else l = mid;
        }
        return r * r;
    }
    
    private boolean check(List<Integer> A, int mid, int k, List<Integer> W) {
        int[][] dp = new int[101][101];
        for (int i = 0; i < 101; i++) {
            for (int j = 0; j < 101; j++) {
                dp[i][j] = Integer.MAX_VALUE / 2;
            }
        }
        for (int i = 0; i <= W.get(0); i++) dp[0][i] = Math.abs(i - A.get(0));
        for (int i = 1; i < A.size(); i++) {
            for (int curr = 0; curr <= W.get(i); curr++) {
                for (int prev = 0; prev <= W.get(i - 1); prev++) {
                    if (Math.abs(curr - prev) > mid) continue;
                    dp[i][curr] = Math.min(dp[i][curr], dp[i - 1][prev] + Math.abs(curr - A.get(i)));
                }
                
            }
        }
        int res = Integer.MAX_VALUE / 2;
        for (int i = 0; i <= W.get(A.size() - 1); i++) res = Math.min(res, dp[A.size() - 1][i]);
        return res <= k;
    }

  

原文地址:https://www.cnblogs.com/hyserendipity/p/13121275.html