Skip to content

【回溯】公平分发饼干

公平分发饼干

给你一个整数数组 cookies ,其中 cookies[i] 表示在第 i 个零食包中的饼干数量。另给你一个整数 k 表示等待分发零食包的孩子数量,所有 零食包都需要分发。在同一个零食包中的所有饼干都必须分发给同一个孩子,不能分开。

分发的 不公平程度 定义为单个孩子在分发过程中能够获得饼干的最大总数。

返回所有分发的最小不公平程度。

  • 2 <= cookies.length <= 8
  • 1 <= cookies[i] <= 105
  • 2 <= k <= cookies.length

回溯

把一个集合划分成K组,使得每组的和的最大值最小”应该只能用回溯才能得到正确答案!贪心一定是错的!

回溯的写法并不难,记录当前路径的最大值即可,抵达叶节点时再取极小。

class Solution {
public:
    int distributeCookies(vector<int>& cookies, int k) {
        int n = cookies.size();
        sort(cookies.begin(), cookies.end(), greater<int>());
        // n^k
        int ans = INT_MAX;
        vector<int> v(k, 0);
        function<void(int, int)> dfs = [&](int i, int mx) {
            // exit dfs
            if (i >= n) {
                ans = min(ans, mx);
                return;
            }
            // choose each group
            for (int j = 0; j < k; j++) {
                v[j] += cookies[i];
                dfs(i + 1, max(mx, v[j]));
                v[j] -= cookies[i];
            }
        };
        dfs(0, 0);
        return ans;
    }
};

二分加速回溯

注意到这个题目的答案也具有单调性,故可以用二分法寻找边界。然而判断函数还是需要回溯才能得到正确答案。

class Solution {
public:

    int distributeCookies(vector<int>& cookies, int k) {
        // binary search, n^k logC
        int n = cookies.size();
        sort(cookies.begin(), cookies.end(), greater<int>());
        // n^k
        auto test = [&](int m) {
            vector<int> v(k, 0);
            bool flag = false;
            function<void(int)> dfs = [&](int i) {
                if (flag) return;
                if (i >= n) {
                    for (int j = 0; j < k; j++) {
                        if (v[j] > m) {
                            flag = false;
                            return;
                        }
                    }
                    flag = true;
                    return;
                }
                for (int j = 0; j < k; j++) {
                    // important pruning!
                    if (v[j] + cookies[i] > m) continue;
                    v[j] += cookies[i];
                    dfs(i + 1);
                    v[j] -= cookies[i];
                }
            };
            dfs(0);
            return flag;
        };
        // search for the left border
        int l = 1, r = 1e9 + 1;
        while (l <= r) {
            int m = (l + r) / 2;
            if (test(m)) r = m - 1;
            else l = m + 1;
        }
        return l;
    }
};