LeetCode:Minimum Path Sum(網格最大路徑和)

題目連接php

Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.html

Note: You can only move either down or right at any point in time.函數


典型的動態規劃問題。測試

設dp[i][j]表示從左上角到grid[i][j]的最小路徑和。那麼dp[i][j] = grid[i][j] + min( dp[i-1][j], dp[i][j-1] );優化

下面的代碼中,爲了處理計算第一行和第一列的邊界條件,咱們令dp[i][j]表示從左上角到grid[i-1][j-1]的最小路徑和,最後dp[m][n]是咱們所求的結果.net

class Solution {
public:
    int minPathSum(vector<vector<int> > &grid) {
        int row = grid.size(),col;
        if(row == 0)return 0;
        else col = grid[0].size();
        vector<vector<int> >dp(row+1, vector<int>(col+1, INT_MAX));
        dp[0][1] = 0;
        for(int i = 1; i <= row; i++)
            for(int j = 1; j <= col; j++)
                dp[i][j] = grid[i-1][j-1] + min(dp[i][j-1], dp[i-1][j]);
        return dp[row][col];
    }
};

 

注意到上面的代碼中dp[i][j] 只和上一行的dp[i-1][j]和上一列的dp[i][j-1]有關,所以能夠優化空間爲O(n)(準確來說空間複雜度能夠是O(min(row,col線程

)))                          本文地址code

class Solution {
public:
    int minPathSum(vector<vector<int> > &grid) {
        int row = grid.size(),col;
        if(row == 0)return 0;
        else col = grid[0].size();
        vector<int >dp(col+1, INT_MAX);
        dp[1] = 0;
        for(int i = 1; i <= row; i++)
            for(int j = 1; j <= col; j++)
                dp[j] = grid[i-1][j-1] + min(dp[j], dp[j-1]);
        return dp[col];
    }
};

問題擴展htm

最大路徑和只須要把上面的遞推公式中的min換成max。blog

如今有個問題,若是兩我的同時從左上角出發,目的地是右下角,兩我的的路線不能相交(即除了出發點和終點外,兩我的不一樣經過同一個格子),使得兩條路徑的和最大。(這和一我的先從左上角到右下角,再回到左上角是相同的問題)。

這是雙線程動態規劃問題:假設網格爲grid,dp[k][i][j]表示兩我的都走了k步,第一我的向右走了i步,第二我的向右走了j步 時的最大路徑和(只須要三個變量就能夠定位出兩我的的位置grid[k-i][i-1] 、 grid[k-j][j-1]),那麼

dp[k][i][j] = max(dp[k-1][i-1][j-1], dp[k-1][i][j], dp[k-1][i-1][j], dp[k-1][i][j-1]) + grid[k-i][i-1] + grid[k-j][j-1]  (咱們假設在起始位置時就已經走了一步)

 

這個方程的意思是從第k-1步到第k步,能夠兩我的都向右走、都向下走、第一個向下第二個向右、第一個向右第二個向下,這四種走法中選擇上一步中路徑和最大的。

 

因爲要保證兩條路線不能相交,即兩我的走的過程當中,有一我的向右走的步數永遠大於另外一我的向右走的步數,咱們不妨設第二我的向右走的步數較大,即dp[k][i][j]中j > i纔是有效的狀態。走到終點的步數爲:網格的行數+網格的列數-1

 

須要注意的是:當走了k步時,某我的向右走的步數必須 > k - 網格的行數,若是向右走的步數 <= k-行數,那麼向下走的步數 = k-向右走的步數 >= 行數,此時超出了網格的範圍。因爲咱們假設了 j > i,所以只要保證 i > k-網格行數便可。

代碼以下:

int max2PathSum(vector<vector<int> > grid)
{
    int row = grid.size(), col = grid[0].size();
    vector<vector<vector<int> > > dp(row+col, vector<vector<int> >(col+1, vector<int>(col+1, 0)));
    for(int step = 2; step <= row+col-2; step++)
        for(int i = max(1, step-row+1); i <= step && i <= col; i++)
            for(int j = i+1; j <= step && j <= col; j++)
            {
                
                dp[step][i][j] = max(max(dp[step-1][i][j], dp[step-1][i-1][j-1]), max(dp[step-1][i-1][j], dp[step-1][i][j-1]));
                dp[step][i][j] += (grid[step-i][i-1] + grid[step-j][j-1]);
            }
    return dp[row+col-2][col-1][col] + 2*grid[row-1][col-1] + 2*grid[0][0];
}

 

咱們最終的目標是dp[row+col-1][col][col] = max{dp[row+col-2][col-1][col-1], dp[row+col-2][col][col], dp[row+col-2][col-1][col], dp[row+col-2][col][col-1]} + 2*grid[row-1][col-1]

因爲dp[row+col-2][col-1][col-1], dp[row+col-2][col][col], dp[row+col-2][col][col-1]都是無效的狀態(dp[k][i][j]中j > i纔是有效的狀態),

因此dp[row+col-1][col][col]  = dp[row+col-2][col-1][col] + 2*grid[row-1][col-1],代碼中最後結果還加上了所在起點的的網格值。

由以上可知,循環中最多隻須要求到了dp[row+col-2][][]。

 

nyoj中 傳紙條(一)就是這個問題,能夠在這一題中測試上述函數的正確性,測試代碼以下:

int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 1; i <= n; i++)
    {
        int row, col;
        scanf("%d%d", &row, &col);
        vector<vector<int> >grid(row, vector<int>(col));
        for(int a = 0; a < row; a++)
            for(int b = 0; b < col; b++)
                scanf("%d", &grid[a][b]);
        printf("%d\n", max2PathSum(grid));
    }
    return 0;
}

 

這個問題還可使用最小費用流來解決,具體能夠參考here

 

 

【版權聲明】轉載請註明出處http://www.cnblogs.com/TenosDoIt/p/3774804.html

相關文章
相關標籤/搜索