1. 程式人生 > >《演算法設計與分析》第十二週作業

《演算法設計與分析》第十二週作業

《演算法設計與分析》第十二週作業

標籤(空格分隔): 課堂作業

文章目錄

姓名:李**
學號:16340114
題目:Burst Balloons(https://leetcode.com/problems/burst-balloons/)


題目概要

給定一串數字,每個數字代表一個氣球,每個氣球都有一個數值。每次扎破一個氣球,可以得到該氣球左邊和右邊以及自身數字之積的硬幣,若果左/右沒有氣球,其數值為1。求能拿到的最大硬幣數

思路

這個題目可以先從最簡單的情況出發,只有一個氣球的時候,只能得到該氣球數值的硬幣數。對於一般情況,即氣球不止一個時(下標從i到j)考慮最後一個需要扎破的氣球。當這個氣球最後被扎破時,其餘被扎破的氣球都能獲得最大的硬幣,而扎破最後選定的氣球k的收益為 n u m s [ i

1 ] n u m s [ k ]
n u m s [ j + 1 ] nums[i-1]*nums[k]*nums[j+1] ,整段氣球的收益為: n u m s [ i 1 ] n u m s [ k ] n u m s [ j + 1 ]   +   c o i n s [ i   t o   k 1 ] + c o i n s [ k + 1   t o   j ] nums[i-1]*nums[k]*nums[j+1]\ +\ coins[i\ to\ k-1] + coins[k+1\ to\ j]
  用coins[i][j]表示nums[i…j]能獲取的最大硬幣數。(包含位置i與j),其值為:
   ( 1 ) c o i n s [ i ] [ j ]   =   0 ,   w h e n   j   <   i (1)coins[i][j]\ =\ 0,\ when\ j\ <\ i
   ( 2 ) c o i n s [ i ] [ j ]   =   n u m s [ i 1 ]     n u m s [ i ]     n u m s [ i + 1 ] ,   w h e n   j   =   i (2)coins[i][j]\ =\ nums[i-1]\ *\ nums[i]\ *\ nums[i+1], when j\ =\ i
   ( 3 ) c o i n s [ i ] [ j ]   =   m a x ( n u m s [ i 1 ]   n u m s [ k ]   n u m s [ j + 1 ]   +   c o i n s [ i ] [ k 1 ]   c o i n s [ k + 1 ] [ j ] ) (3)coins[i][j]\ =\ max(nums[i-1]\ * nums[k]\ * nums[j+1]\ +\ coins[i][k-1]\ coins[k+1][j])
                           , i < = k < = j ,   w h e n   j   >   i \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ,i<=k<=j, when j\ >\ i
  特別地,當nums下標越界時,其值為1。對(3)式中的coins[i][k-1],當 k 1 < i k-1<i 時,其值為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;
    }
};