最小路径和(dfs+动规)

leetcode 64. Minimum Path Sum

一、问题描述

给定一个填充非负数的m×n网格,找到一条从左上角到右下角的路径,该路径使沿路径上的所有数字的总和最小。

注意:您只能在任何时间点向下或向右移动。

【举例】

输入:
[
  [1,3,1]
  [1,5,1]
  [4,2,1]
]
输出:7

说明:因为路径1-3-1-1-1使总和最小化。

本题解法思想与笔者之前写过的一篇方法如出一辙,可参考学习: 三角数字自上而下求最值和【dfs+动规】

二、解题算法

方法1 -- 常规DFS--会超时

/**************************************************************
leetcode 64. Minimum Path Sum

Author:tmw
date:2018-5-26
**************************************************************/
#include <stdio.h>
#include <stdlib.h>
/**
方法一:常规dfs -- 会超时
    终止条件(数据非法):i>=rowSize||j>=colSize
    收敛条件(获得一种可行解):i==rowSize&&j==colSize --- grid[i][j]
    剪枝条件--这里同终止条件
    递归方向:
            向下:dfs(grid,colSize,rowSize,i++,j)
            向右:dfs(grid,colSize,rowSize,i,j++)
**/
#include <limits.h>
#define min(a,b) ( a<b?a:b )
int dfs(int** grid, int rowSize, int colSize, int i, int j)
{
    //终止条件
    if( i>=rowSize || j>=colSize ) return INT_MAX;

    //收敛条件
    if( i==rowSize-1 && j==colSize-1 ) return grid[i][j];

    //递归方向
    return min(dfs(grid,rowSize,colSize,i+1,j),dfs(grid,rowSize,colSize,i,j+1))+grid[i][j];
}

int minPathSum(int** grid, int gridRowSize, int gridColSize)
{
    return dfs(grid,gridRowSize,gridColSize,0,0);
}

方法2 -- 加备忘录DFS--accept

/**
方法二:加备忘录的dfs
    递归方式与上一样
    加一个二维数组用来存储中间结果,表示走到当前的[i][j]位置的min path
**/
#define min(a,b) ( a<b?a:b )
#include <limits.h>
int dfs_MEM( int** grid, int rowSize, int colSize, int i, int j, int** record )
{
    //终止条件
    if( i>=rowSize || j>=colSize ) return INT_MAX;

    if(record[i][j]>0) return record[i][j];

    //收敛条件
    if( i==rowSize-1 && j==colSize-1 ) return grid[i][j];

    record[i][j]=min(dfs_MEM(grid,rowSize,colSize,i+1,j,record),dfs_MEM(grid,rowSize,colSize,i,j+1,record))+grid[i][j];

    return record[i][j];
}

int minPathSum(int** grid, int gridRowSize, int gridColSize)
{
    /**为结果数组申请空间并赋值**/
    int** record = (int**)malloc(gridRowSize*sizeof(int*));
    int i,j;
    for(i=0; i<gridRowSize; i++)
       record[i] = (int*)malloc(gridColSize*sizeof(int));
    for(i=0; i<gridRowSize; i++)
        for(j=0; j<gridColSize; j++)
            record[i][j] = 0;

    return dfs_MEM(grid,gridRowSize,gridColSize,0,0,record);
}

方法3 -- 动态规划--accept

/**
方法三:动态规划
采用动态规划思想,要求到达[gridRowSize-1][gridColSize-1]的最小开销路径,
则:
1)要么是从到[gridRowSize-1][gridColSize-2]的最小开销+grid[gridRowSize-1][gridColSize-1]
2)要么是从到[gridRowSize-2][gridColSize-1]的最小开销+grid[gridRowSize-1][gridColSize-1]
所以,递归表达式为:f[i][j] = min(f[i-1][j],f[i][j-1])+a[i][j]
**/
#define min(a,b) (a<b?a:b)
int minPathSum(int** grid, int gridRowSize, int gridColSize)
{
    //申请f空间
    int i,j;
    int** f=(int**)malloc(gridRowSize*sizeof(int*));
    for(i=0;i<gridRowSize;i++)
        f[i]=(int*)malloc(gridColSize*sizeof(int));

    //初始化f的边界--- f[i][j]为到达点[i][j]所经过的最小开销
    f[0][0] = grid[0][0];
    for(i=1; i<gridRowSize; i++)
        f[i][0] = f[i-1][0] + grid[i][0];
    for(j=1; j<gridColSize; j++)
        f[0][j] = f[0][j-1] + grid[0][j];

    //填满f[][]数组
    for(i=1; i<gridRowSize; i++)
        for(j=1; j<gridColSize; j++)
            f[i][j] = min(f[i-1][j],f[i][j-1])+grid[i][j];

    return f[gridRowSize-1][gridColSize-1];

}


梦想还是要有的,万一实现了呢~~~~ヾ(◍°∇°◍)ノ゙~~~


猜你喜欢

转载自blog.csdn.net/qiki_tangmingwei/article/details/80462021