题意:给出一个n*n的方阵,要求从(1,1)出发到点(n,n)的一条路径,并且经过的点的值为负数的个数小于等于k,输出路径上点的值之和最大值,若无法达到终点,则输出impossible
思路:定义四维数组f[i][j][num][v],表示在点i,j处用了k个负数从v方向来的路径之和最大值
v=0表示从上面来,那么可以往下、左、右递归,v=1表示从左边来,可以向下、右递归,v=2表示从右边来,可以向左、向下递归
代码:
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
#define inf -200000000
long long f[80][80][8][3];
bool vis[80][80][8][3];//0为从上面来,1为从左边来,2为从右边来
int a[80][80];
int n,k;
long long Max(long long x,long long y,long long z)
{
if(x>=y && x>=z)return x;
else if(y>=x && y>=z)return y;
else
return z;
}
long long DP(int i,int j,int num,int v)
{
int kk;
long long x,y,z,mmax;
if(vis[i][j][num][v])
return f[i][j][num][v];
vis[i][j][num][v]=1;
if(num==k && a[i][j]<0)//大于所给k,那么直接不能到达,所以inf
return f[i][j][num][v]=inf;
if(i==n && j==n)
return f[i][j][num][v]=a[i][j];
if(a[i][j]<0)
kk=num+1;
else
kk=num;
if(v==0)
{
x=y=z=inf;
if(i<n)
x=DP(i+1,j,kk,0);
if(j>1)
y=DP(i,j-1,kk,2);
if(j<n)
z=DP(i,j+1,kk,1);
mmax=Max(x,y,z);
if(mmax!=inf && mmax+a[i][j]>f[i][j][num][v])
f[i][j][num][v]=mmax+a[i][j];
}
else if(v==1)
{
x=y=z=inf;
if(i<n)
x=DP(i+1,j,kk,0);
if(j<n)
y=DP(i,j+1,kk,1);
mmax=Max(x,y,z);
if(mmax!=inf && mmax+a[i][j]>f[i][j][num][v])
f[i][j][num][v]=mmax+a[i][j];
}
else
{
x=y=z=inf;
if(i<n)
x=DP(i+1,j,kk,0);
if(j>1)
y=DP(i,j-1,kk,2);
mmax=Max(x,y,z);
if(mmax!=inf && mmax+a[i][j]>f[i][j][num][v])
f[i][j][num][v]=mmax+a[i][j];
}
return f[i][j][num][v];
}
void solve(int g)
{
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
for(int num=0; num<=k; num++)
for(int v=0; v<=2; v++)
f[i][j][num][v]=inf;//定义为最小的
memset(vis,0,sizeof(vis));
long long ans;
ans=DP(1,1,0,0);
if(ans!=inf)
printf("Case %d: %lld\n",g,ans);
else
printf("Case %d: impossible\n",g);
}
int main()
{
int g=0;
while(scanf("%d%d",&n,&k)!=EOF)
{
if(!n && !k)break;
g++;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
scanf("%d",&a[i][j]);
solve(g);
}
return 0;
}