[leetcode] 1231 Divide Chocolate


https://leetcode.com/contest/biweekly-contest-11/problems/divide-chocolate/

 

        這道題的題目意思就是,一個巧克力有n格,每個格子有不同的甜度,將巧克力切k次,選擇甜度最低的那塊,問怎么切能夠使得甜度最低的那塊巧克力甜度最大。

        比賽的時候第一反應這里有一個很明顯的遞推關系:從切k-1塊到切k塊,從k-1加上連續的1~n格就能得到下一個狀態,於是很快就得到了一個超時的n3 dp:

class Solution {
public:
    int n;
    int maximizeSweetness(vector<int>& sweetness, int K) {
        n = sweetness.size();
        vector<vector<int>> dp(n, vector<int>(K + 5, 0));
      
        for(int i = 0;i < n;i++)
        {
            if(i == 0) dp[i][0] = sweetness[i];
            else dp[i][0] = sweetness[i] + dp[i - 1][0];
        }
        for(int k = 1;k <= K; k++)
        {
            for(int i = 0;i < n; i++)
            {        
                int sum = 0;
                for(int j = i + 1;j < n;j++)
                {
                    sum += sweetness[j];
                    dp[j][k] = max(dp[j][k], min(dp[i][k - 1], sum));
                }
            }
        }
        return dp[n - 1][K];
    }
};

        再仔細一看這道題的輸入數據量是10^4。這道題還存在着一個臨界點的問題,它符合了滿足某一個臨界點(分成k+1份,每份至少有x個),我們就可以假定這個x值,並判斷是否滿足條件(最多能切成幾份)。也就是說我們可以使用二分猜答案,假設答案為某個值,如果題目存在這么一個臨界條件,我們就能通過二分找到這個臨界值。

        最終的算法復雜度為:O(nlogn)

class Solution
{
public:
    int getK(vector<int>& sweetness, int min)
    {
        int sum = 0;
        int k = 0;
        for(int i = 0;i < sweetness.size();i++)
        {
            sum += sweetness[i];
            if(sum >= min)
            {
                k++;
                sum = 0;
            }
        }
        return k;
    }
    int maximizeSweetness(vector<int>& sweetness, int K) 
    {
        int low = 0;
        int high = 1 << 30;
      
        while(low < high)
        {
            if(high - low == 1)
            {
                if(getK(sweetness, high) >= K + 1) return high;
                else return low;
            }
            int mid = (high - low) / 2 + low;
            
            if(getK(sweetness, mid) >= K + 1)
            {
                low = mid;
            }
            else
            {
                high = mid;
            }
        }
        return low;
    }
};

一道類似的題:https://leetcode.com/problems/capacity-to-ship-packages-within-d-days/

        題意是輪船一天運一次貨,要求最少D天把貨物運到(條件存在限制),求輪船的最小容量(求邊界結果)。

class Solution {
public:
    int getDay(vector<int>& weights, int capacity)
    {
        int sum = 0;
        int day = 0;
        for(int i = 0;i < weights.size(); i++)
        {
            sum += weights[i];
            if(sum > capacity)
            {
                day++;
                sum = weights[i];
            }
        }
        if(sum != 0) day++;
        return day;
    }
    int shipWithinDays(vector<int>& weights, int D) {
        int high = accumulate(weights.begin(), weights.end(), 0);
        int low = *max_element(weights.begin(), weights.end());

        while(low < high)
        {
            if(low == high - 1)
            {
                if(getDay(weights, low) <= D) return low;
                else return high;
            }
            int mid = (high - low) / 2 + low;
            if(getDay(weights, mid) <= D)
            {
                high = mid;   
            }
            else
            {
                low = mid;
            }
        }
        return low;
    }
};

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM