题意给出一个n*n的方阵,从(1,1)出发到(n,n)目的是找出一条路径,这条路径上的点的值为负数的个数要小于等于k,在满足这个条件之下,使路径之和最大,如果无法找到这样的路径(即负数的个数一定大于k)则输出impossible
定义状态为四维,f[i][j][k][v],表示从v方向来到当前的点(i,j),已经用掉的负数的个数是k,所能得到的最大值。V=0表示从上面递归而来的,接下来可以向下,左,右递归。V=1表示从左边递归而来,接下来可以向下,右递归。V=2表示从右边递归而来,接下来可以向下,左递归。
然后就是注意初始化的问题和一些值要记得赋初值的问题,整个记忆所搜索的思路还是比较容易理解的
#include#include #define MAXN 80#define MAXK 10#define INF -198873434long long f[MAXN][MAXN][MAXK][3];bool visit[MAXN][MAXN][MAXK][3];int a[MAXN][MAXN];int N,K;void input(){ int i,j; for(i=1; i<=N; i++) for(j=1; j<=N; j++) scanf("%d",&a[i][j]);}long long max(int t1 , int t2 , int t3){ if(t1>=t2 && t1>=t3) return t1; else if(t2>=t1 && t2>=t3) return t2; else return t3;}long long DP(int i , int j ,int k ,int v){ int kk; long long t1,t2,t3,m; if(visit[i][j][k][v]) return f[i][j][k][v]; visit[i][j][k][v]=1; if(k==K && a[i][j]<0) return f[i][j][k][v]=INF; if(i==N && j==N) return f[i][j][k][v]=a[i][j];// f[i][j][k][v]=INF; if(a[i][j]<0) kk=k+1; else kk=k; if(v==0) //从上而来 { t1=t2=t3=INF; //要记得赋初值因为有递归不能进行这三个变量不一定能得到一个返回值 if(i<=N-1) t1=DP(i+1,j,kk,0); //向下递归,对于下一层而言是从上而来,只能向下左右递归 if(j>=2) t2=DP(i,j-1,kk,2); //向左递归,对于下一层而言是从右而来,只能向下左递归 if(j<=N-1) t3=DP(i,j+1,kk,1); //向右递归,对于下一层而言是从左而来,只能向下右递归 m=max(t1,t2,t3); if(m!=INF && m+a[i][j]>f[i][j][k][v]) f[i][j][k][v]=m+a[i][j]; } else if(v==1) //从左而来 { t1=t2=t3=INF; //要记得赋初值因为有递归不能进行这三个变量不一定能得到一个返回值 if(i<=N-1) t1=DP(i+1,j,kk,0); if(j<=N-1) t2=DP(i,j+1,kk,1); m=max(t1,t2,t3); if(m!=INF && m+a[i][j]>f[i][j][k][v]) f[i][j][k][v]=m+a[i][j]; } else //从右而来 { t1=t2=t3=INF; //要记得赋初值因为有递归不能进行这三个变量不一定能得到一个返回值 if(i<=N-1) t1=DP(i+1,j,kk,0); if(j>=2) t2=DP(i,j-1,kk,2); m=max(t1,t2,t3); if(m!=INF && m+a[i][j]>f[i][j][k][v]) f[i][j][k][v]=m+a[i][j]; } return f[i][j][k][v];}void solve(int T){ int i,j,k,v; long long ans; for(i=1; i<=N; i++) for(j=1; j<=N; j++) for(k=0; k<=K; k++) for(v=0; v<=2; v++) f[i][j][k][v]=INF; memset(visit, 0, sizeof(visit)); ans=DP(1,1,0,0); if(ans!=INF) printf("Case %d: %lld\n",T,ans); else printf("Case %d: impossible\n",T);}int main(){ int T=0; while(scanf("%d%d",&N,&K)!=EOF) { if(!N && !K) break; T++; input(); solve(T); } return 0;}