UVA - 10913 Walking on a Grid

题目大意:给出n,k,然后给出一个n*n的图,从(1,1)通过向下,左和右三个方向,走到(n,n)点,途中不可以走相同的位置,并且路过的位置为负数的个数<= k, 找出一条路使得这条路上的值之和最大。不能到达输出impossible


解题思路:记忆化搜索,用四维数组去记录最优解,vis二维数组表示当前访问状态,dp[x][y][i][j]表示位置x,y的地方,当路过的负数个数为i且从j代表的方向进入时的最优解。


我写完的时候超时了,但是改了一下方向就过了,估计是方向的缘故将最优解记录住了,所以优化比较大。


#include <cstring>
#include <cstdio>
#include <algorithm>
#include <climits>
using namespace std;

long long DP[80][80][7][3];
int vis[80][80][7][3], mat[80][80], n;

bool judge(int a) {
	return a >= 0 && a < n;
}

long long DPS(int x, int y, int k, int d) {
	long long &m = DP[x][y][k][d];
	if (vis[x][y][k][d])
		return m;
	vis[x][y][k][d] = true;

	if (k == 0 && mat[x][y] < 0)
		return INT_MIN;

	if (x == n-1 && y == n-1)
		return m = mat[x][y];

	if (mat[x][y] < 0)
		k--;

	int r, c;

	if (d != 1) {
		r = x, c = y + 1;
		if (judge(c) && DPS(r, c, k, 0) != INT_MIN)
			m = max(m, DP[r][c][k][0] + mat[x][y]);
	}

	if (d != 0 && x != n - 1) {
		r = x, c = y - 1;
		if (judge(c) && DPS(r, c, k, 1) != INT_MIN)
			m = max(m, DP[r][c][k][1] + mat[x][y]);
	}

	if (x != n - 1) {
		r = x + 1, c = y;
		if (DPS(r, c, k, 2) != INT_MIN)
			m = max(m, DP[r][c][k][2] + mat[x][y]);
	}
	return m;
}

int main() {
	int kase = 0, k;
	while (scanf("%d%d", &n, &k), n) {
		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++) {
				scanf("%d", &mat[i][j]);
				for (int l = 0; l <= k; l++ )
					DP[i][j][l][0] = DP[i][j][l][1] = DP[i][j][l][2] = INT_MIN;
			}

		memset(vis, 0, sizeof(vis));
		printf("Case %d: ", ++kase);
		if (DPS(0, 0, k, 0) != INT_MIN)
			printf("%lld\n", DPS(0, 0, k, 0));
		else
			printf("impossible\n");
	}
	return 0;
}


你可能感兴趣的:(UVA - 10913 Walking on a Grid)