题目描述:在一个n*m的方格中,m为奇数,放置有n*m个数,方格中间的下方有一人,此人可按照正前方相临的五个方向(方格)前进但不能越出方格。人每走过一个方格必须取此方格中的数。要求找到一条从底到顶的路径,使其数相加之和为最大。输出和的最大值。
如果我们预设方格的左下角为 (0,0) 的话,那么右上角为(m, n),而人的出发点是([m / 2], 0).
人只能走五个方向的格子,所以能直接到达的点(x, y)为(x - 2, y - 1), (x - 1, y - 1), (x, y - 1), (x + 1, y - 1), (x + 2, y - 1)中的一条路径产生。我们要从这里面挑一条和最大的路径。所以F(x, y) = Max{F(x - 2, y - 1), F(x - 1, y - 1), F(x, y - 1), F(x + 1, y - 1), F(x + 2, y - 1)} +Value(x, y)。
边界条件为:F([m / 2, 0]) = 0, F(x, 0) = -无穷(1 <= x <= m && x != [m / 2])
从顶部第一行第一列看的话,最大和的值为a[1][n] + maxn(a[1][n - 1], a[2][n - 1], a[3][n - 1]),maxn函数为求三个数中的最大值。
所以由此我们可以推断出状态转移方程a[i][j] = a[i][j] + maxn(a[i - 2][j - 1] ...a[i + 2][j - 1]);
以下是代码实现:
#include <cstdio>
#include <iostream>
using namespace std;
int main()
{
int a[6][7] = {
{16,4,3,12,6,0,3},
{4,-5,6,7,0,0,2},
{6,0,-1,-2,3,6,8},
{5,3,4,0,0,-2,7},
{-1,7,4,0,7,-5,6},
{0,-1,3,4,12,4,2}
};
int b[6][7], c[6][7];
int i, j, k, max, flag;
for(i = 0; i < 6; i ++)
for(j = 0; j < 7; j ++)
b[i][j] = a[i][j], c[i][j] = -1;
for(i = 1; i < 5; i ++)
for(j = 0; j < 7; j ++) {
max = 0;
for(k = j - 2; k <= j + 2; k ++) {
if(k < 0) continue;
else
if(k > 6) break;
else
if(b[i][j] + b[i- 1][k] > max)
max = b[i][j] + b[i-1][k], flag = k;
}
b[i][j] = max, c[i][j] = flag;
}
for(j = 1; j <= 5; j ++) { // i = 5
max = 0;
for(k = j - 2; k <= j + 2; k ++) {
if(k < 0) continue;
else
if(k > 6) break;
else
if(b[i][j] + b[i - 1][k] > max)
max = b[i][j] + b[i - 1][k], flag = k;
}
b[i][j] = max, c[i][j] = flag;
}
max = 0;
for(j = 1; j <= 5; j ++)
if(b[i][j] > max)
max = b[i][j], flag = j;
printf("从底到顶最大和值为:%d\n",max);
printf("从底到顶分别取数:");
printf("%d", a[i][flag]);
for(j = i; j > 0; j --) {
flag = c[j][flag];
printf(" %d", a[j - 1][flag]);
}
printf("\n");
return 0;
}
版权声明:本文为qq_41024297原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。