《演算法設計與分析》第十二週作業
阿新 • • 發佈:2018-11-26
《演算法設計與分析》第十二週作業
標籤(空格分隔): 課堂作業
文章目錄
姓名:李**
學號:16340114
題目:Burst Balloons(https://leetcode.com/problems/burst-balloons/)
題目概要
給定一串數字,每個數字代表一個氣球,每個氣球都有一個數值。每次扎破一個氣球,可以得到該氣球左邊和右邊以及自身數字之積的硬幣,若果左/右沒有氣球,其數值為1。求能拿到的最大硬幣數
思路
這個題目可以先從最簡單的情況出發,只有一個氣球的時候,只能得到該氣球數值的硬幣數。對於一般情況,即氣球不止一個時(下標從i到j)考慮最後一個需要扎破的氣球。當這個氣球最後被扎破時,其餘被扎破的氣球都能獲得最大的硬幣,而扎破最後選定的氣球k的收益為
,整段氣球的收益為:
用coins[i][j]表示nums[i…j]能獲取的最大硬幣數。(包含位置i與j),其值為:
特別地,當nums下標越界時,其值為1。對(3)式中的coins[i][k-1],當
時,其值為0(k-1可能越界),coins[k+1][j]同理。
最後的答案為coins[0][nums.size()-1]。
具體實現
用二維陣列儲存coins的狀態。在迴圈時,要先計算長度小的氣球串再到長度大的氣球串。注意判斷nums與coins的邊界狀態即可。
心得
這個動態規劃問題的關鍵在於一般情況的硬幣數該怎麼算。想到只有一個氣球時的抉擇,把這個抉擇推廣到一般情況,再稍微琢磨一下,便可求得coins的狀態表達式。
原始碼:
#define leftNum(x) (x==0 ? 1 : nums[x-1])
#define rightNum(x) (x==length-1 ? 1 : nums[x+1])
#define max(a, b) (a>b ? a : b)
class Solution
{
public:
int maxCoins(vector<int>& nums)
{
int length = nums.size();
if (length == 0)
return 0;
int** coins = new int* [length];
for (int i = 0; i < length; ++i)
coins[i] = new int [length];
for (int i = 0; i < length; ++i)
for (int j = 0; j < length; ++j)
coins[i][j] = 0;
for (int segment = 0; segment < length; ++segment)
{
for (int i = 0; i+segment < length; ++i)
{
int j = i + segment;
for (int k = i; k <= j; ++k)
{
int leftCoins = (k==i ? 0 : coins[i][k-1]);
int rightCoins = (k==j ? 0 : coins[k+1][j]);
int lastBurstKCoins = leftNum(i) * nums[k] * rightNum(j) + leftCoins + rightCoins;
coins[i][j] = max(coins[i][j], lastBurstKCoins);
}
}
}
int answer = coins[0][length-1];
for (int i = 0; i < length; ++i)
delete coins[i];
delete coins;
return answer;
}
};