这个题目一开始使用三维数组进行记录,dp[x][y][k]分别记录的是x,y,点处还可以走k个负点,通过回溯同时记忆化的方式来进行计算。这样有个非常可笑的错误就是同一个点如果通过两条不同路径从该点左方和右方到达这个点并且同时k的值也相同,他们的值应该不同但由于记忆化直接就会返回先计算的一个值就会漏掉情况,所以这一题要使用四维dp,增加一维记录这个点从哪个方向过来同时还可以解决左右来回走动的问题。
#include<iostream>
#include<cstring>
using namespace std;
int dp[80][80][10][5];
bool b[80][80][10][5];
int m[80][80];
int n,maxx;
#define INF 0xffffff
int tem = 1;
int DP(int x,int y,int k,int f){
if(k<0)return -INF;
if(b[x][y][k][f])return dp[x][y][k][f];
if(x==n-1&&y==n-1)return m[n-1][n-1];
int aa = -INF,bb=-INF,cc=-INF;
if(x!=n-1){
if(m[x+1][y]<0){
aa = DP(x+1,y,k-1,1);
}else{
aa = DP(x+1,y,k,1);
}
}
if(y!=0&&f!=3){
if(m[x][y-1]<0){
bb = DP(x,y-1,k-1,2);
}else{
bb = DP(x,y-1,k,2);
}
}
if(y!=n-1&&f!=2){
if(m[x][y+1]<0){
cc = DP(x,y+1,k-1,3);
}else{
cc = DP(x,y+1,k,3);
}
}
b[x][y][k][f] = 1;
if(aa==-INF&&bb==-INF&&cc==-INF)return dp[x][y][k][f] = -INF;
return dp[x][y][k][f] = max(aa,max(bb,cc))+m[x][y];
}
int main(){
while(cin >> n >> maxx&&(n+maxx)){
memset(dp,0,sizeof(dp));
memset(b,0,sizeof(b));
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
cin >> m[i][j];
}
if(m[0][0]<0)maxx--;
int ans = DP(0,0,maxx,0);
if(ans==-INF)cout<<"Case "<<tem++<<": impossible"<<endl;
else{
cout<<"Case "<<tem++<<": "<<ans<<endl;
}
}
}
用四维数组一次就ac了。。