[蓝桥杯][2014年第五届真题]地宫取宝

题目链接:地宫取宝



解题思路:动态规划。在每一个位置的状态考虑,当前这个位置的状态是由哪些状态转移过来的。


dp[i][j][u][v]表示在(i,j)这个位置,拿到u个物品,且这些物品的最大价值是v。


我们可以考虑当前位置(i,j)拿不拿当前这个物品,如果不拿那么可以从dp[i-1][j][u][v]、dp[i][j-1][u][v]转移过来,表示上一个位置已经拿到了u个物品最大价值为v的。如果拿则可以从dp[i-1][j][u-1][c]、dp[i][j-1][u-1][c]转移过来,表示上一个位置拿了u-1个,并且最大价值为c(c为小于v的数),最后再把最后手上可能拿的价值的方案数加起来即可。


ps:因为这道题的所有物品价值范围是0…120…12,可以把他们全部都递增,范围就变成了1…131…13,因为我们记录的是方案数,只关心各个物品之间的大小关系,具体数值不影响答案,但是这样的做法可以把00作为一个特殊边界来处理

#include<bits/stdc++.h>
#define x first
#define y second
#define mem(h) memset(h,-1,sizeof h)
#define mcp(a,b) memcpy(a,b,sizeof b)
using namespace std;
typedef long long LL;
typedef unsigned long long ull; 
typedef pair<int,int>PII;
typedef pair<double,double>PDD;
namespace IO{
	inline LL read(){
		LL o=0,f=1;char c=getchar();
		while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
		while(c>='0'&&c<='9'){o=o*10+c-'0';c=getchar();}
		return o*f;
	}
}using namespace IO;
//#############以上是自定义技巧(可忽略)########## 
const int N=50+7,M=2e5+7,INF=0x3f3f3f3f,mod=1e9+7,P=131;
int dp[N][N][13][14]; 
int n,m,k;
int w[N][N];
int main(){
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>w[i][j];
			w[i][j]++;//这里是需要注意的点,把所有的权值+1,更好处理也不影响结果
		}
	}
	dp[1][1][1][w[1][1]]=1;//如果拿起(1,1)的物品
	dp[1][1][0][0]=1;//如果不拿
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(i==1&&j==1)continue;//这个位置可以跳过
			for(int u=0;u<=k;u++){//枚举到达当前位置可能拿了几个物品
				for(int v=0;v<=13;v++){//枚举到达当前位置手中的最大物品价值
					int &val=dp[i][j][u][v];
					val=(val+dp[i-1][j][u][v])%mod;//不拿当前位置的物品时可能从这些状态转移过来
					val=(val+dp[i][j-1][u][v])%mod;
					if(u>0&&v==w[i][j]){//如果到达当前位置手中有物品,并且物品最大价值等于当前位置的物品价值,那么可以拿起当前物品
						for(int c=0;c<v;c++){//可以从这些状态转移过来
							val=(val+dp[i-1][j][u-1][c])%mod;
							val=(val+dp[i][j-1][u-1][c])%mod;
						}
					} 
				}
			}
		}
	}
	int res=0;
	for(int i=0;i<=13;i++){
		res=(res+dp[n][m][k][i])%mod;//把最后手上可能拿的最大价值方案数相加
	}
	cout<<res<<endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值