题目的意思就是要从(1,1)那个格子走到(n,n)那个格子.并且途中只能经过k个负数.
而且走的时候方向不能向上,其他方向都可以,还有走过的点不能再走.问路上经过的点的值加起来最大是多少,如果走不到就输出impossible;
用来记忆的f数组要开四维,记录位置(x,y),经过的负数的个数,还有方向,刚开始没有考虑方向,错了很多发,因为就算同一个位置,经过同样多的负数,如果方向不同,也是不一样的状态:
然后直接一步步回溯就行了.需要注意的是,之前的从左边过来,现在就不能在回左边去,之前从右边过来,现在就不能再回右边去.
AC代码;
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define ll long long
const int INF = -0x3f3f3f3f;
const ll N = 80;
ll f[N][N][7][5];
int dir[3][2] = {{0,1} ,{1,0} ,{0 ,-1}};
ll grid[N][N];
int vis[N][N][7][5];
int viss[N][N];
int n,k;
ll dp(ll x, ll y , ll t,ll d) {
ll& ans = f[x][y][t][d];
if(vis[x][y][t][d])
return ans;
if(t == 0) {
vis[x][y][t][d] = 1;
return ans = INF;
}
if(x == n && y == n) {
vis[x][y][t][d] = 1;
return ans = grid[x][y];
}
ans = INF;
for(int i = 0 ; i < 3 ;i++) {
int nx = x + dir[i][0];
int ny = y + dir[i][1];
if(d != 1 & d + i == 2)
continue;
if(nx >= 1 && ny >= 1 && nx <= n && ny <= n && !viss[nx][ny]) {
viss[nx][ny] = 1;
if(grid[x][y] < 0) {
ll temp = dp(nx,ny,t - 1 , i);
if(temp != INF)
ans = max(ans , temp + grid[x][y]);
}
else {
ll temp = dp(nx,ny,t , i);
if(temp != INF)
ans = max(ans ,temp + grid[x][y]);
}
viss[nx][ny] = 0;
}
}
vis[x][y][t][d] = 1;
return ans;
}
int main () {
int cas = 1;
while(scanf("%d%d",&n,&k) && (n + k)) {
memset(vis , 0 ,sizeof(vis));
memset(viss , 0 ,sizeof(viss));
for(int i = 1 ; i<= n ; i++) {
for (int j = 1 ; j <= n ; j++) {
scanf("%lld",&grid[i][j]);
}
}
if(grid[n][n] >= 0)
k++;
ll res = dp(1,1,k,1);
if(res == INF)
printf("Case %d: impossible\n",cas++);
else
printf("Case %d: %lld\n",cas++ , res);
}
}