1. 程式人生 > >動態規劃(3)格子取數問題

動態規劃(3)格子取數問題

問題描述:
有n*n個格子,每個格子裡有正數或者0,從最左上角往右下角走。一共走2次,(即從左上角走到右下角走兩次),把所有經過的格子裡的數加起來,求總和的最大值。如果兩次經過同一個格子,則最後求得的總和中該格子中的數只加一次。
思路:
避免“不顧全域性,只看區域性”(貌似叫貪心)
動態規劃保證全域性最優。
程式碼如下:

const int N = 202;
const int inf = 1000000000;//無窮大
int dp[N*N][N][N];
bool IsValid(int step,int x1,int x2,int n)
{
    int y1 = step - x1,y2 = step
- x2; return ((x1 >= 0) && (x1 < n) && (x2 >=0) &&(x2 < n) && (y1 >= 0) && (y1 < n) && (y2 >= 0) && (y2 < n)); } int GetValue(int step,int x1,int x2,int n) { return IsValid(step,x1,x2,n) ? dp[step][x1][x2]:(-inf); } //狀態表示dp[step][i][j],並且i <= j
//在第step步,兩人分別在第i行和第j行的最大部分,時間複雜度是O(n^3),空間複雜度為O(n^3) int MaxPathSum(int a[N][N],int n) { int P = n*2-2; int i,j,step; for (i = 0;i < n;i++) { for (j = i;j < n;j++) dp[0][i][j] = -inf; } } dp[0][0][0] = a[0][0]; for (step = 1;step <= P;i++) { for (i = 0;i < n;i++) { for
(j = i;j < n;j++) { dp[step][i][j] = -inf; if (!IsValid(step,i,j,n))//非法位置 { continue; } //對於合法的位置進行深度優先搜尋 if (i != j) { dp[step][i][j] = max(dp[step][i][j],GetValue(step-1,i-1,j-1,n)); dp[step][i][j] = max(dp[step][i][j],GetValue(step-1,i-1,j,n)); dp[step][i][j] = max(dp[step][i][j],GetValue(step-1,i.j-1,n)); dp[step][i][j] = max(dp[step][i][j],GetValue(step-1,i,j,n)); } else { dp[step][i][j] = max(dp[step][i][j],GetValue(step-1,i-1,j-1,n)); dp[step][i][j] = max(dp[step][i][j],GetValue(step-1,i-1,j,n)); dp[step][i][j] = max(dp[step][i][j],GetValue(step-1,i,j,n)); dp[step][i][j] += a[i][step-i]; } } } return dp[P][n-1][n-1]; }