1. 程式人生 > >動態規劃初步 劉汝佳字數 數字三角形

動態規劃初步 劉汝佳字數 數字三角形

有一個由非負整陣列成的三角形,第一行只有一個數,除了最下行之外每個數左下方和右下方各有一個數 如圖所示

 

從第一行的數開始,每次可以往左下或右下走一格,直到走到最下行,把沿途經過的數全部加起來,如何走才能使得這個和最大?

分析:

一看到題目我們很自然的可以想到用回溯法(DFS)做,即每次都選擇靠左的格子走,走到頭後再回溯選擇靠右的格子,按<左,右>的順序遍歷完所有的路徑

程式碼如下:

#include<iostream>
using namespace std;

int a[11] = {0,29,9,5,12,7,26,6,14,15,8
};//假設有四層 int max = -1, sum = 0; int shuzi(int i, int j)//計算第i層第j個的數字在a陣列的第幾個 { int x = 0; for (int l = 1; l <= i - 1; l++) { x += l; } x += j; return x; } int dfs(int i, int j) { if (i==5) { if (sum > max) max = sum; return 0; } sum
+= a[shuzi(i, j)]; dfs(i + 1, j); dfs(i + 1, j + 1); sum -= a[shuzi(i, j)]; return 0; } int main(int argc, char* argv[]) { dfs(1, 1); cout << max<<endl; return 0; }

時間複雜度是2^n,指數級的,n一旦大了就會超時

所以用狀態轉移方程來發現每項的依賴項

方程如下:

d(i,j)=a(i,j)+max{d(i+1,j),d(i+1,j+1)};

程式碼如下:

#include<iostream>
using namespace std;

int a[20] = {0,1,2,3,4,5,6,7,8,9,12,0,0,0,0,0,0,0,0,0};
int max(int a, int b)
{
    return a > b ? a : b;
}
int shuzhi(int i, int j)
{
    int x = 0;
    for (int l = 1; l <= i - 1; l++)
    {
        x += l;
    }
    x += j;
    return x;
}
int solve(int i, int j)
{
    int x=shuzhi(i, j);
    return a[x]+(i==4?0:max(solve(i+1,j),solve(i+1,j+1)));
    
}
int main(int argc, char* argv[])
{
    cout << solve(1, 1)<<endl;
    return 0;
}

已經知道了每項的依賴項,就可以避免重複計算

#include<iostream>
using namespace std;

int a[20] = {0,13,11,8,12,7,26,6,14,15,8};
int dp[10][10] = { {0,0} };
int max(int a, int b)
{
    return a > b ? a : b;
}
int shuzi(int i, int j)
{
    int x = 0;
    for (int l = 1; l <= i - 1; l++)
    {
        x += l;
    }
    x += j;
    return x;
}
int solve(int i, int j)
{
    for (int k = 1; k <= 4; k++)
        dp[4][k] = a[shuzi(4, k)];
    for (int k = 3; k >= 1; k--)
        for (int l = 1; l <= k; l++)
            dp[k][l] = a[shuzi(k, l)]+ max(dp[k + 1][l], dp[k + 1][l + 1]);
    return dp[i][j];
}
int main(int argc, char* argv[])
{
    cout << solve(1, 1) << endl;
    return 0;
}

簡化版:

#include<iostream>
using namespace std;

int a[20] = { 0,1,2,3,4,5,6,7,8,9,10};
int dp[10][10] = { { 0,0 } };
int max(int a, int b)
{
    return a > b ? a : b;
}
int shuzi(int i, int j)
{
    int x = 0;
    for (int l = 1; l <= i - 1; l++)
    {
        x += l;
    }
    x += j;
    return x;
}
int solve(int i, int j)
{
    if (dp[i][j] >= 0) return dp[i][j];
    return a[shuzi(i, j)] + (i==4?0:max(solve(i+1,j), solve(i + 1, j+1)));

}
int main(int argc, char* argv[])
{
    memset(dp, -1, sizeof(dp));
    cout << solve(1, 1) << endl;
    return 0;
}