使用一个四维数组来进行记忆化dfs
x,y表示坐标,z表示当前已拿物品,Max表示当前拿到的最大价值物品
那么ok[x][y][z][Max]表示 在点(x,y)处拿了z个物品最大价值为Max这个状态 到 点(n,m)处拿了k物品 这个状态有多少条走法。
其中在初始位置拿的最大价值应该是-1,因为后面会有0价值的物品。
判出递归边界有两个情况。
情况1:不拿最后一个物品就已经有k个物品了
情况2:可以拿最后一个物品并且拿了之后才够k个物品
也分两个情况,
情况1:该点物品不能拿,衍生出2条路径,只能向下走和向右走 。
情况2:该点物品可以拿,则可以衍生出4条路径,拿物品向下走,拿物品向右走,不拿向下走,不拿向右走。
x,y表示坐标,z表示当前已拿物品,Max表示当前拿到的最大价值物品
那么ok[x][y][z][Max]表示 在点(x,y)处拿了z个物品最大价值为Max这个状态 到 点(n,m)处拿了k物品 这个状态有多少条走法。
其中在初始位置拿的最大价值应该是-1,因为后面会有0价值的物品。
判出递归边界有两个情况。
情况1:不拿最后一个物品就已经有k个物品了
情况2:可以拿最后一个物品并且拿了之后才够k个物品
其他情况均返回0。
也分两个情况,
情况1:该点物品不能拿,衍生出2条路径,只能向下走和向右走 。
情况2:该点物品可以拿,则可以衍生出4条路径,拿物品向下走,拿物品向右走,不拿向下走,不拿向右走。
最后取模即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
ll ans[52][52];
ll ok[52][52][20][15];
ll n,m,k;
const int MOD=1000000007;
ll dfs(ll x,ll y,ll z,ll Max){
if(x>n||y>m||z>k)return ok[n][m][k][Max]=0;//先判断边界
if(x==n&&y==m)//再是递归边界
{
if(z==k)return ok[n][m][k][Max]=1;//不拿最后一个物品就已经有k个物品了
if(ans[x][y]>Max&&z+1==k)return ok[n][m][k][Max]=1;//可以拿最后一个物品并且拿了之后才够k个物品
}
if(ok[x][y][z][Max]!=-1)return ok[x][y][z][Max];//返回已经算出来的路径
ok[x][y][z][Max]=0;//将-1置0
if(ans[x][y]>Max)//能拿的话额外走两条拿的路径
{
ok[x][y][z][Max]+=dfs(x+1,y,z+1,ans[x][y]);
ok[x][y][z][Max]+=dfs(x,y+1,z+1,ans[x][y]);
}
ok[x][y][z][Max]+=dfs(x+1,y,z,Max);//不管能不能拿都要走不拿的两条路径
ok[x][y][z][Max]+=dfs(x,y+1,z,Max);
return ok[x][y][z][Max]%1000000007;//取模
}
/*ll dfs(ll x,ll y,ll z,ll Max)//纯递归搜索
{
if(x>n||y>m||z>k)return 0;
if(x==n&&y==m)
{
if(z==k)return 1;
if(ans[x][y]>Max&&z+1==k)return 1;
}
if(ans[x][y]>Max)
{
return dfs(x+1,y,z+1,ans[x][y])+dfs(x,y+1,z+1,ans[x][y])+dfs(x+1,y,z,Max)+dfs(x,y+1,z,Max);
}
return dfs(x+1,y,z,Max)+dfs(x,y+1,z,Max);
}*/
int main()
{
memset(ok,-1,sizeof(ok));
scanf("%lld%lld%lld",&n,&m,&k);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
scanf("%lld",&ans[i][j]);
}
printf("%lld",dfs(1,1,0,-1));//因为有0价值的物品
}