14蓝桥杯 地宫取宝

使用一个四维数组来进行记忆化dfs
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价值的物品 
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值