給你一個披薩,它由 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; } };