[Acwing蓝桥杯DP] 1212. 地宫取宝

题目:1212. 地宫取宝 - AcWing题库

大意描述:有一个 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;
}

 

posted @   秦末  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
1 博文导航目录
点击右上角即可分享
微信分享提示