Leetcode 64.最小路径和(动态规划)(动态数组解决)
题目分析
给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例:
输入:
3 3
1 3 1
1 5 1
4 2 1
输出:
7
图片均来自来自Leetcode题解
解题思路
***** 关于动态规划的问题有部分内容引自Hollis Chuang的这篇文章 ****
由题目要求我们要找出路径的最小值,但是遍历太过庞大,我们很容易可以想到用动态规划解题:
动态规划的一般步骤
- 确定定义数组的意义;
- 根据递归的思想确立递推关系式;
- 确定初始值;
- 利用初始值与递推关系式正向求目标结果;
1.确定定义数组的意义:
根据题目要求,我们的目标是求出最小路径的数字和,那么我们定义的数组的含义就是到m,n的最小路径的数字和。
dp[m][n]就代表了从坐标原点到m,n的最小路径的数字和。
但是实际上的m,n为m-1,n-1。因为坐标原点为0,0;
2.根据递归思想确定递推关系式
从结果来看,我们要想办法将dp[x][y]与前几项相联系起来,倒过来走,我们可以发现只可以从上方或者下方到达dp[x][y],我们要求最小值,那么便可以得出
dp[x][y]=min(dp[x][y-1],dp[x-1][y])+num[x][y]
代表的意义是从左边或从上边来的最小值,再走一步,加上该位置本身含有的数字。
这就是我们的递推关系式。
3.确定初始值。
初始值就是不能用递推关系计算的情况。
那么啥条件下不能用递推关系式计算呢?
当然是x=0或y=0时,此时只有可能从上方过来或者是从左边过来,不能用递推关系式来解决,
那么我们就需要计算初始值
dp[x][0]=dp[x-1][0]+num[x][0];
当坐标为(0,0)时dp[0][0]=num[0][0]
for (i = 1; i < m; i++)
{
dp[i][0] = dp[i - 1][0] + x[i][0];
}
for (j = 1; j < n; j++)
{
dp[0][j] = dp[0][j - 1] + x[0][j];
}
我们完成了图中的这一步。,蓝色部分为初始化
注:图片均来自来自Leetcode题解
4.利用初始值与关系式求目标值
由于左边与最上边已经初始化,我们要从**坐标(1.1)**开始计算值知道(m-1,n-1)
for (i = 1; i < m; i++)
{
for (j = 1; j < n; j++)
{
dp[i][j] = Min(dp[i - 1][j], dp[i][j - 1]) + x[i][j];
}
}
这样我们就求出了dp[m-1][n-1].
求解dp[x-1][y-1]
代码展示(利用动态数组)
#include<stdio.h>
#include<stdlib.h>
void Free(int** x, int col);//释放动态数组
int Min(int x, int y);//求最小值
int minway(int** x, int m, int n);//求最小路径的和
int main()
{
int m, n;
scanf("%d %d", &m, &n);
int i, j;
int** x;
x = (int**)malloc(sizeof(int*) * m);
for (i = 0; i < m; ++i)
{
x[i] = (int*)malloc(sizeof(int) * n);
}
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
scanf("%d\n", &x[i][j]);
}//动态二维数组的基本操作,建立与输出。
int num;
num = minway(x, m, n);
printf("%d\n", num);
Free(x, n);释放内存
return 0;
}
int minway(int** x, int m, int n)
{
int i;
int** dp;
dp = (int**)malloc(sizeof(int*) * m);
for (i = 0; i < m; ++i)
{
dp[i] = (int*)malloc(sizeof(int) * n);
}//二维数组的建立。
i = 0;
int j = 0;
dp[0][0] = x[0][0];//初始化
//初始化最左边
for (i = 1; i < m; i++)
{
dp[i][0] = dp[i - 1][0] + x[i][0];
}
//初始化最上边
for (j = 1; j < n; j++)
{
dp[0][j] = dp[0][j - 1] + x[0][j];
}
//利用初始化与递推关系式求解
for (i = 1; i < m; i++)
{
for (j = 1; j < n; j++)
{
dp[i][j] = Min(dp[i - 1][j], dp[i][j - 1]) + x[i][j];
}
}
return dp[m-1][n-1];
}
int Min(int x, int y)
{
return x < y ? x : y;
}
void Free(int** x, int col)
{
int i = 0;
for (i = 0; i < col; i++)
{
free(x[i]);
}
free(x);
}