算法题_礼物的最大价值(滚动数组思想)

题目:在一个m * n的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格,直到到达棋盘的右下角。给定一个棋盘以及上面的礼物,请计算最多能拿到多少价值的礼物?

思路:这是一个典型的动态规划题目。我们定义函数f(i,j)表示到达坐标(i,j)的格子时能拿到的礼物总和的最大值。我们可以通过格子(i-1,j)和(i,j-1)到达(i,j)所以我们可以定义f(i,j) = max(f(i-1,j), f(i,j - 1) + gift(i,j))。gift(i,j)表示格子(i,j)里的礼物价值。

我们用递归来分析问题,但由于有大量重复计算,我们用循环来编写代码会提高很多效率。为了缓存中间结果,我们需要一个二维数组。数组中中坐标为(i,j)的元素表示到达这个坐标的格子时能拿到的礼物价值总和的最大值。

解析来我们用C++进行编程:

int GetMaxValue(const int& numbers, int rows, int cols)
{
	if(number == nullptr || rows <= 0 || cols <= 0)
		return 0;

	int** maxvalues = new int*[rows];
	for(int i = 0; i < rows; i++)
		maxvalues[i] = new int[cols];
	
	for(int i = 0; i < rows; i++)
	{
		for(int j = 0; j < cols; j++)
		{
			left = 0;
			up = 0;
			if(i > 0)
				up = maxvalues[i - 1][j];

			if(j > 0)
				left = maxvalues[i][j - 1];

			maxvalues[i][j] = std::max(up,left) + numbers[i*cols + j];
		}
	}
	int max = maxvalues[rows - 1][cols - 1];
	for(int i = 0; i < rows; i++)
		delete[] maxvalues[i];
	delete[] maxvalues;
	return max;			
}

优化思路:我们知道,到达坐标(i,j)的格子时能够拿到的礼物的最大价值只依赖坐标为(i - 1, j)和(i, j - 1)的两个格子,因此第i- 2行及更上面的所有格子礼物的最大价值其实没有必要保存下来。我们可以用一维数组来替代前面代码中的二维矩阵maxvalues。该一维数组的长度为棋盘的列数n。该数组前面j个数字分别是当前第i行前面j个格子礼物的最大价值,而之后的数字分别保存前面第i - 1行n-j个格子礼物的最大价值。

接下来我们用C++进行编程:

int GetMaxValue(const int& numbers, int rows, int cols)
{
	if(numbers == nullptr || rows <= 0; cols <= 0)
		return 0;

	int* maxvalues = new int[cols];
	for(int i = 0; i < rows; i++)
	{
		for(int j = 0; j <cols; j++)
		{
			up = 0;
			left = 0;
			if(i > 0)
				up = maxvalues[j];
			if(j > 0)
				left = maxvalues[j - 1];
			maxvalues[j] = std::max(up, left) + numbers[i*cols + j];
		}
	}
	int max = maxvalues[cols - 1];
	delete[] maxvalues;
	return max;
}

你可能感兴趣的:(算法题)