【動態規劃專題】6:打氣球的最大分數


《程序員代碼面試指南--IT名企算法與數據結構題目最優解》 左程雲 著ios

打氣球的最大分數程序員

【題目】
給定一個數組arr,表明一排有分數的氣球。每打爆一個氣球都能得到分數,假設打爆氣球的分數爲X,得到分數的規則以下:
1)若是被打爆氣球的左邊有沒有被打爆的氣球,找到離被打爆氣球最近的氣球,假設分數爲L;
若是被打爆氣球的右邊有沒有被打爆的氣球,找到離被打爆氣球最近的氣球,假設分數爲R。得到分數爲L*X*R。
2)若是被打爆氣球的左邊有沒有被打爆的氣球,找到離被打爆氣球最近的氣球,假設分數爲L;
若是被打爆氣球的右邊全部氣球都已經被打爆。得到分數爲L*X。
3)若是被打爆氣球的左邊全部的氣球都已經被打爆;
若是被打爆氣球的右邊有沒有被打爆的氣球,找到離被打爆氣球最近的氣球,假設分數爲R。得到分數爲X*R。
4)若是被打爆氣球的左邊和右邊全部的氣球都已經被打爆。得到分數爲X。面試

目標是打爆全部氣球,得到每次打爆的分數。經過選擇打爆氣球的順序,能夠獲得不一樣的總分,
請返回能得到的最大分數。算法

【舉例】
arr = [3,2,5]數組

若是先打爆3,得到3*2;再打爆2,得到2*5;最後打爆5,得到5,最後總分21.
若是先打爆3,得到3*2;再打爆5,得到2*5;最後打爆2,得到2,最後總分18.
若是先打爆2,得到3*2*5;再打爆3,得到3*5;最後打爆5,得到5,最後總分50.
若是先打爆2,得到3*2*5;再打爆5,得到3*5;最後打爆3,得到3,最後總分48.
...等等,有6中打氣球的順序(全拍列)
能得到的最大分數爲50.數據結構

 

#include <iostream> #include <vector> #include <algorithm> #include <stdlib.h>
using namespace std; void Printdp(int ** dp, int rows, int cols) { cout << "Printdp--------------start" << endl; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { cout << dp[i][j] << ","; } cout << endl; } cout << "Printdp--------------End" << endl; cout << endl; } int MaxNum(int A, int B) { if (A > B) { return A; } else { return B; } }

 

/////////////////////////////////////////////////////////////方法1:暴力遞歸求解
//打爆arr[L...R]範圍上的全部氣球,返回最大的分數 //假設arr[L-1]和arr[R+1]必定沒有被打爆
int process(int *arr, int length, int L, int R) { if (L == R)//若是arr[L...R]範圍上只有一個氣球,直接打爆便可
 { return arr[L - 1] * arr[L] * arr[R + 1]; } //最後打爆arr[L]的方案與最後打爆arr[R]的方案,先比較一下
    int max = MaxNum(arr[L - 1] * arr[L] * arr[R + 1] + process(arr, length, L + 1, R), arr[L - 1] * arr[R] * arr[R + 1] + process(arr, length, L, R - 1)); //嘗試中間位置的氣球最後被打爆的每一種方案
    for (int i = L + 1; i < R; i++) { max = MaxNum(max, arr[L - 1] * arr[i] * arr[R + 1] + process(arr, length, L, i - 1) + process(arr, length, i + 1, R)); } return max; } int MaxCoins1(int *arr, int length) { if (arr == nullptr || length <= 0) { return 0; } if (length == 1) { return arr[0]; } int N = length; int *help = new int[N + 2]; help[0] = 1; help[N + 1] = 1; for (int i = 0; i < N; i++) { help[i + 1] = arr[i]; } int iResult = process(help, N, 1, N); return iResult; }

 

/////////////////////////////////////////////////////////////解法2:
int MaxCoins2(int *arr, int length) { if (arr == nullptr || length <= 0) { return 0; } if (length == 1) { return arr[0]; } int N = length; int * help = new int[N + 2]; help[0] = 1; help[N + 1] = 1; for (int i = 0; i <N; i++) { help[i + 1] = arr[i]; } int **dp = new int*[N + 2]; for (int i = 0; i < N + 2; i++) { dp[i] = new int[N + 2]; } for (int i = 0; i < N + 2; i++) { for (int j = 0; j < N + 2; j++) { dp[i][j] = 0; } } /////對角線上的. L==R的狀況...
    for (int i = 1; i <= N ; i++) { dp[i][i] = help[i - 1] * help[i] * help[i + 1]; } for (int L = N; L >= 1; L--) { for (int R = L + 1; R <= N; R++) { //求解dp[L][R],表示help[L...R]上打爆全部氣球的最大分數

            ///最後打爆 help[L] 的方案
            int finalL = help[L - 1] * help[L] * help[R + 1] + dp[L + 1][R]; //最後打爆 help[R] 的方案
            int finalR = help[L - 1] * help[R] * help[R + 1] + dp[L][R - 1]; //最後打爆 help[L] 和最後打爆 help[R] 的方案比較一下
            dp[L][R] = max(finalL, finalR); //嘗試中間位置的氣球最後被打爆的每一種方案
            for (int i = L + 1; i < R; i++) { dp[L][R] = max(dp[L][R], help[L - 1] * help[i] * help[R + 1] + dp[L][i - 1] + dp[i + 1][R]); } } } int  iResult = dp[1][N]; Printdp(dp, N + 2, N + 2); return iResult; }

 

//////////////////////////////和解法2相同,這是地道的C++方式的解法。用到了vector
int MaxCoins3() { int n = 3; vector<int> arr(n + 2, 1); for (int i = 1; i <= n; i++) { cin >> arr[i]; } vector<vector<int>> dp(n + 2, vector<int>(n + 2, 0)); for (int i = 1; i <= n; i++) { dp[i][i] = arr[i - 1] * arr[i] * arr[i + 1]; } for (int l = n; l >= 1; l--) for (int r = l + 1; r <= n; r++) //dp[l][r]表示在[l,r]上打爆全部氣球的最大分數
 { int finall = arr[l - 1] * arr[l] * arr[r + 1] + dp[l + 1][r]; int finalr = arr[l - 1] * arr[r] * arr[r + 1] + dp[l][r - 1]; dp[l][r] = max(finall, finalr); for (int i = l + 1; i <= r - 1; i++) dp[l][r] = max(dp[l][r], arr[l - 1] * arr[i] * arr[r + 1] + dp[l][i - 1] + dp[i + 1][r]); } for (int i = 0; i < n + 1; i++) { for (int j = 0; j < n + 1; j++) { cout << dp[i][j] << ","; } cout << endl; } cout << endl; cout << dp[1][n] << endl; }

 

////===============測試用例====================
void test1() { int arr[] = { 3,2,5 }; int iResult1 = MaxCoins1(arr, sizeof(arr) / sizeof(int)); cout << "iResult1:" << iResult1 << endl; int iResult2 = MaxCoins2(arr, sizeof(arr) / sizeof(int)); cout << "iResult2:" << iResult2 << endl; } int main() { test1(); cout << endl; system("pause"); return 0; }

 

備註:一臉懵逼,沒看懂。先把代碼記錄下來吧。測試

相關文章
相關標籤/搜索