问题描述:
在一个m×n的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向左或者向下移动一格直到到达棋盘的右下角。给定一个棋盘及其上面的礼物,请计算你最多能拿到多少价值的礼物?
解题思路:
动态规划。
对于每个格子(第0行、第0列除外)它可能是从正上方的格子过来能得到最大值,也可能从正左方的格子过来取得最大值,
所以当到达(i,j)格子时,礼物的最大值为:
当前格子礼物的价值 + max(到达左方格子的最大总价值,到达上方格子的最大总价值)
即状态转移方程:dp[i][j]=max(dp[i-1][j],dp[i][j-1]) + values[i][j];
int getMaxValue_solution1(const int* values, int rows, int cols)
{
if(values==nullptr||rows<=0||cols<=0) return 0;
int dp[rows][cols];
memset(dp,0,sizeof(dp));
dp[0][0]=values[0];
for(int i=0;i<rows;i++)
{
for(int j=0;j<cols;j++)
{
if(i>0) dp[i][j]=max(dp[i][j],dp[i-1][j]+values[i*cols+j]);
if(j>0) dp[i][j]=max(dp[i][j],dp[i][j-1]+values[i*cols+j]);
}
}
return dp[rows-1][cols-1];
}
书上的代码似乎更加简单易懂:
int getMaxValue_solution1(const int* values, int rows, int cols)
{
if(values==nullptr||rows<=0||cols<=0) return 0;
int dp[rows][cols];
memset(dp,0,sizeof(dp));
for(int i=0;i<rows;i++)
{
for(int j=0;j<cols;j++)
{
int up=0,left=0;
if(i>0) up=dp[i-1][j];
if(j>0) left=dp[i][j-1];
dp[i][j]=max(up,left)+values[i*cols+j];
}
}
return dp[rows-1][cols-1];
}
可以优化空间,只使用一个一维数组来存储状态:
int getMaxValue_solution2(const int* values, int rows, int cols)
{
if(values==nullptr||rows<=0||cols<=0) return 0;
int dp[cols];
memset(dp,0,sizeof(dp));
for(int i=0;i<rows;i++)
{
for(int j=0;j<cols;j++)
{
int up=0,left=0;
if(i>0) up=dp[j];
if(j>0) left=dp[j-1];
dp[j]=max(up,left)+values[i*cols+j];
}
}
return dp[cols-1];
}