AI 摘要

这道dfs题目让小明在地宫取宝时只能向右或向下行走。小明可以选择拿或不拿每个格子中的宝贝,若宝贝价值高于手中的宝贝则可拿取。求取恰好k件宝贝的行动方案数。通过记忆化搜索,实现了对每种行动方案数的计算。

地宫取宝

原题地址:8.地宫取宝 - 蓝桥云课 (lanqiao.cn)

题目描述

X 国王有一个地宫宝库。是 n×m 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。

地宫的入口在左上角,出口在右下角。

小明被带到地宫的入口,国王要求他只能向右或向下行走。

走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。

当小明走到出口时,如果他手中的宝贝恰好是 k 件,则这些宝贝就可以送给小明。

请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这 k 件宝贝。

输入描述

输入一行 3 个整数,用空格分开:n, m, k(1≤ n, m≤50,1≤ k ≤12)n,m,k (1≤n,m≤50,1≤k≤12)。

接下来有 n 行数据,每行有 m 个整数 Ci​ (0≤Ci​≤12) 代表这个格子上的宝物的价值。

输出描述

要求输出一个整数,表示正好取 k 个宝贝的行动方案数。该数字可能很大,输出它对 109+7109+7 取模的结果。

输入输出样例

输入:

2 2 2

1 2

2 1

输出:

2

代码实现

#include<bits/stdc++.h>

using namespace std;
int n,m,k;
int a[55][55];//输入所给数组值所分配的内存空间
int dp[55][55][15][15];//开创记忆化的存储空间
//因为只进行向下走和向右走,所有写成这个样子,不明白的可以在了解以下笛卡尔积,向下是x轴,向右是y轴(一般情况下)
int dx[]={1,0};
int dy[]={0,1};
int p=1e9+7;//索取余数
//dfs()里面写x,y,mx,cnt分别代表更新的坐标,最大值,宝物数目
long long dfs(int x,int y,int mx,int cnt){
    if(x==n&&y==m)  return cnt==k;//这个是结束临界条件,到最后结束跳出
    if(dp[x][y][mx][cnt]!=-1)   return dp[x][y][mx][cnt];//进行记忆化搜索的地方,如果之前保存过这个值就不用再次计算而是直接使用保存过的值(值不会因为后续深搜改变的改变而是不变)
    long long res=0;//后续进行记忆化存储的给予赋值
    for(int i=0;i<2;i++){
    //进行向下或者向右的搜索
        int nx=x+dx[i];
        int ny=y+dy[i];
        if(nx<1||ny<1||nx>n||ny>m)continue;
   //拿这个东西
        if(a[nx][ny]>mx&&cnt<k) res=(res+dfs(nx,ny,a[nx][ny],cnt+1))%p;
   //不拿这个东西
        res=(res+dfs(nx,ny,mx,cnt))%p;
    }
   //进行记忆化搜索的重要部分
    return dp[x][y][mx][cnt]=res;
}


int main(){
   //将dp数组置为-1,不置为0是因为宝物价值可能为0出现异议
    memset(dp,-1,sizeof dp);
    cin>>n>>m>>k;

    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
            a[i][j]++;//宝物的价值可以为0,++是为了防止宝物价值为0的情况,所有宝物价值都+1就是为了避免价值0的情况。你造一个数据,如果存在价值为0的物品就会少路径答案,如果不存在价值为0的情况,那这个a[i][j]++有没有都行
   //这里的++是为了让宝物价值最小也为1,问题问的是路线情况,并不用担心价值问题
        }
   //对一开始的宝物拿和不拿都进行深搜获得最终答案         
    cout<<(dfs(1,1,0,0)+dfs(1,1,a[1][1],1))%p<<endl;


    return 0;
}

届ける言葉を今は育ててる
最后更新于 2024-04-04