[Acwing蓝桥杯DP] 1212. 地宫取宝
大意描述:有一个 n * m 的矩阵,从左上角到右下角走 ,每经过一个点 ,如果当前位置的宝物价值 大于手里的最大宝物价值 可以选择拿或者不拿
求 当走到右下角的时候 手中的宝物恰好为 k 件的 总方案数量 。
数据范围: 1<=n,m<=50
1<=k<=12
0<=c<=12 // c表示的是每个位置的宝物的价值大小
题目分析:
看到这个题 有很多的约束条件 基本上是融合了2. 01背包问题 - AcWing题库 和 1015. 摘花生 - AcWing题库 这两个题
考虑从左上到右下 如果到一个点 如果该点的值 大于手里最大值(一定大于手里的任意一个价值)记录一下手里的最大值
本题还有个限制条件,就是到底右下角的时候,手中的宝物件数是k,所以也要记录一下手里有多少个宝物
那么我们用闫氏DP分析法来分析一下
(DP分析自:www.acwing.com/solution/content/7116/)偷个懒QAQ!
这个题的难点在于:状态计算部分,联想到01背包问题,对于每个物品,都有取或不取两种选择,而不取是肯定可以的,要取的话,要满足背包能放下这个条件
初始化比较简单 就是 初始化刚开始的起点
查看代码
f[1][1][1][g[1][1]]=1;//这是刚开始起点取的情况
f[1][1][0][0]=1;//这是刚开始起点不取的情况
我们可以注意到 起点不取这个物品的时候 初始化该点的最大价值是0 这里是用了个小技巧 用0代表什么都没有的初始状态
所以我们要将所有的物品价值递增 范围就变成了1~13 ,这就需要在刚开始读取价值时候 将价值加1 。这样的化,如果后面的物品价值是0时候也能取
因为我们记录的是方案数,只关心各个物品之间的大小关系,具体数值不影响答案,但是这样的做法可以把0作为一个特殊边界来处理。
(当然也可以赋-1,不同的理解)
那么这道题基本上就解决了
代码:
查看代码
#include <bits/stdc++.h>
using namespace std;
const int N=55,M=13,MOD=1e9+7;
int f[N][N][M][M+1];
int n,m,k;
int g[N][N];
int main()
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>g[i][j];
g[i][j]++;
}
}
f[1][1][1][g[1][1]]=1;
f[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<=M;v++)
{
int &val=f[i][j][u][v];
val=(val+f[i-1][j][u][v])%MOD;
val=(val+f[i][j-1][u][v])%MOD;
if(u>0&&v==g[i][j])
{
for(int c=0;c<v;c++)
{
val=(val+f[i-1][j][u-1][c])%MOD;
val=(val+f[i][j-1][u-1][c])%MOD;
}
}
}
}
}
}
int res=0;
for(int i=0;i<=M;i++)
{
res=(res+f[n][m][k][i])%MOD;
}
cout<<res<<endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人