版权声明:本文为博主原创学习笔记,如需转载请注明来源。 https://blog.csdn.net/SHU15121856/article/details/82694596
面试题47:礼物的最大价值
在一个m×n的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向左或者向下移动一格直到到达棋盘的右下角。给定一个棋盘及其上面的礼物,请计算你最多能拿到多少价值的礼物?
之前Python课也做过这题,因为f(i,j)只依赖左边的一个礼物和上边的一个礼物,可以仅用一个数组将路径堵死向下刮,而不需要保存整个矩阵。
#include<bits/stdc++.h>
using namespace std;
//给出礼物矩阵的一维数组形式,行数,列数,求从矩阵中能获取的礼物的最大值
int getMaxValue_solution(const int* values, int rows, int cols) {
if(values == nullptr || rows <= 0 || cols <= 0)//输入合法性检查
return 0;
//拦路数组:0~j-1=>f(i,0)~f(i,j-1);j~cols=>f(i-1,j)~f(i-1,cols-1)
int* maxValues = new int[cols];
for(int i = 0; i < rows; ++i) {//每一行
for(int j = 0; j < cols; ++j) {//行内从左到右
int left = 0;//左边的礼物价值
int up = 0;//上边的礼物价值
if(i > 0)//i>0时上边礼物存在
up = maxValues[j];//f(i-1,j)存在mV[j]位置
if(j > 0)//j>0时左边礼物存在
left = maxValues[j - 1];//f(i,j-1)存在mV[j-1]位置
//当前位置的礼物最大价值=左边和上边中大价值的一个+当前位置价值
maxValues[j] = max(left, up) + values[i * cols + j];
}
}
//最后跑完了整个矩阵,右下角位置的最大价值是该数组最右元素
int maxValue = maxValues[cols - 1];
delete[] maxValues;
return maxValue;
}
int main() {
int values[][4] = {
{ 1, 10, 3, 8 },
{ 12, 2, 9, 6 },
{ 5, 7, 4, 11 },
{ 3, 7, 16, 5 }
};
cout<<getMaxValue_solution((int *)(values),4,4)<<endl;
return 0;
}
感觉这种省空间的做法很精妙,从上面图中可以看出,这个数组的前半部分(蓝色部分)在行内从左到右循环时逐渐建立起来,而后半部分(紫色部分)则是上一行的循环中计算出而保留在数组内的,在前半部分扩张时逐步地覆盖掉了上次计算的后半部分。
另外,数组中指示当前考察的元素(绿色部分)每次使用到了其左边和其上边的两个元素,这两个元素正式这个数组中“前半部分”和“后半部分”交界之处。