LeetCode 1388. Pizza With 3n Slices(3n 塊披薩)(DP)

給你一個披薩,它由 3n 塊不同大小的部分組成,現在你和你的朋友們需要按照如下規則來分披薩:

你挑選 任意 一塊披薩。
Alice 將會挑選你所選擇的披薩逆時針方向的下一塊披薩。
Bob 將會挑選你所選擇的披薩順時針方向的下一塊披薩。
重複上述過程直到沒有披薩剩下。
每一塊披薩的大小按順時針方向由循環數組 slices 表示。

請你返回你可以獲得的披薩大小總和的最大值。

 

示例 1:

 

輸入:slices = [1,2,3,4,5,6]
輸出:10
解釋:選擇大小爲 4 的披薩,Alice 和 Bob 分別挑選大小爲 3 和 5 的披薩。然後你選擇大小爲 6 的披薩,Alice 和 Bob 分別挑選大小爲 2 和 1 的披薩。你獲得的披薩總大小爲 4 + 6 = 10 。

 

這條比較難的一點是論證:

題目可以轉換爲,取任意 n/3 個不相鄰的數字的最大和。

 

1、首先顯然相鄰的兩個數字是不可能同時取到的。

2、任意長度爲 n/3 的不相鄰的子序列都可以被取到。

  嘗試簡單論證一下,

  用0表示不選擇,1表示選擇,當選擇不相鄰的n/3個數字之後,001001001 這樣的序列可以表示爲一種選取方法。

  顯然,存在某個1的周圍有至少三個0,如 0010 或 0100 (由於是一個圓 首尾時相連接的)

  因爲如果不存在的話,則序列只能爲 010101... 顯然 1 的個數會大於 n/3

  然後先選取這樣的 1 和周圍的兩個 0 ,那麼,剩下還是會有一個 0,(不會出現兩個1相鄰)

  則剩下的序列還是滿足最開始的條件,繼續以同樣的規則選擇直到結束最後剩下010。

  舉例說明:

  001010100

  先取第一個1和旁邊的0 變爲 010100

  取後面的1和旁邊的0 變爲 010 最後全部取走。

 

 

如果能想到上面的結論,剩下的就只是一個簡單的DP了,DP[i][j] 表示取i塊,最後一塊序列爲j的最大值,由於第一塊和最後一塊不能同時取,所以需要計算兩次。其實和這道題蠻像的 https://leetcode-cn.com/problems/house-robber-ii/

class Solution {
public:
    int maxSizeSlices(vector<int>& slices) {
        int n = slices.size();
        int select = n / 3;
        int dp1[select + 1][n];
        int dp2[select + 1][n];
        memset(dp1, 0, sizeof dp1);
        memset(dp2, 0, sizeof dp2);
        dp1[1][0] = slices[0];
        dp2[1][1] = slices[1];
        for (int i = 1; i <= select; i++) {
            for (int j = 2; j < n; j++) {
                for (int k = 0; k < j - 1; k++) {
                    dp1[i][j] = max(dp1[i][j], dp1[i-1][k] + slices[j]);
                    dp2[i][j] = max(dp2[i][j], dp2[i-1][k] + slices[j]);
                }
            }
        }
        int ans = 0;
        for (int i = 0; i < n - 1; i++) {
            ans = max(ans, dp1[select][i]);
        }
        for (int i = 0; i < n; i++) {
            ans = max(ans, dp2[select][i]);
        }
        return ans;
    }
};

 

三層循環可以簡化爲兩層循環

class Solution {
public:
    int maxSizeSlices(vector<int>& slices) {
        int n = slices.size();
        int select = n / 3;
        int dp1[select + 1][n];
        int dp2[select + 1][n];
        memset(dp1, 0, sizeof dp1);
        memset(dp2, 0, sizeof dp2);
        dp1[1][0] = slices[0];
        dp2[1][1] = slices[1];
        int max1, max2;
        for (int i = 1; i <= select; i++) {
            max1 = dp1[i-1][0];
            max2 = dp2[i-1][0];
            for (int j = 2; j < n; j++) {
                dp1[i][j] = max1 + slices[j];
                dp2[i][j] = max2 + slices[j];
                max1 = max(max1, dp1[i-1][j-1]);
                max2 = max(max2, dp2[i-1][j-1]);
            }
        }
        int ans = 0;
        for (int i = 0; i < n - 1; i++) {
            ans = max(ans, dp1[select][i]);
        }
        for (int i = 0; i < n; i++) {
            ans = max(ans, dp2[select][i]);
        }
        return ans;
    }
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章