格子取数问题

有n*n个格子,每个格子里有正数或者0,从最左上角往最右下角走,只能向下和向右,一共走两次(即从左上角走到右下角走两趟),把所有经过的格子的数加起来,求最大值SUM,且两次如果经过同一个格子,则最后总和SUM中该格子的计数只加一次。

#define N 6
//使用滚动数组,因为每次状态计算只要用到前一次的记录即可
int dp[2][N][N] = { 0 };


/*坐标是否满足要求*/
bool isVaild(int step, int x1, int x2, int n) {
	//step-x=y
	if ((x1 >= 0) && (x1 < n) && (step - x1 >= 0) && (step - x1 < n)
			&& (x2 >= 0) && (x2 < n) && (step - x2 >= 0) && (step - x2 < n)) {
		return true;
	}
	return false;
}

int getNum(int step, int x1, int x2, int n) {
	return isVaild(step, x1, x2, n) ? dp[step % 2][x1][x2] : 0;
}

int cellMax(int matrix[N][N], int n) {
	int endStep = 2 * n - 2;	//走到末尾需要步数

	dp[0][0][0] = matrix[0][0];
	for (int step = 1; step <= endStep; ++step) {
		int curIndex = step % 2;
		for (int i = 0; i < n; ++i) {
			for (int j = i; j < n; ++j) {	//j>=i保证不交叉
				if (!isVaild(step, i, j, n)) {
					continue;
				}
				/*不管格子是否一致都有x1,x2相对于格子上上, 左左, 上左,由于x1<=x2,所以左上不一定成立*/
				dp[curIndex][i][j] = max(dp[curIndex][i][j],
						getNum(step - 1, i, j, n));
				dp[curIndex][i][j] = max(dp[curIndex][i][j],
						getNum(step - 1, i - 1, j - 1, n));
				dp[curIndex][i][j] = max(dp[curIndex][i][j],
						getNum(step - 1, i - 1, j, n));

				if (i != j) {	//当前状态不同格子
					dp[curIndex][i][j] = max(dp[curIndex][i][j],
							getNum(step - 1, i, j - 1, n));
					//加2次
					dp[curIndex][i][j] += matrix[i][step - i]
							+ matrix[j][step - j];
				} else {
					/* i==j
					 * matrix[i][step-i]只加一次
					 * 并且i<=j
					 * 则 i>j-1 不计算*/
					dp[curIndex][i][j] += matrix[i][step - i];
				}
			}
		}
//		cout << step << endl;
//		printMatrix(dp, N);
	}
	return dp[endStep % 2][n - 1][n - 1];
}


你可能感兴趣的:(格子取数问题,动态规划)