《算法设计与分析》第十二周作业

《算法设计与分析》第十二周作业

标签(空格分隔): 课堂作业

姓名:李**
学号: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;
    }
};

猜你喜欢

转载自blog.csdn.net/Ray0758/article/details/84496880