历届试题 地宫取宝 (较难DFS或DP递推)

本博客介绍了一个关于地宫寻宝的问题,玩家在限定的行动路径中选择是否拾取价值更高的宝藏,最终计算出能够获得指定数量宝藏的所有行动方案数。问题通过输入地图大小、宝藏价值和目标宝藏数量,输出符合条件的行动方案数,结果对特定数值取模。


Link:http://lx.lanqiao.org/problem.page?gpid=T120


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

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

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

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

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

  请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这k件宝贝。
输入格式
  输入一行3个整数,用空格分开:n m k (1<=n,m<=50, 1<=k<=12)

  接下来有 n 行数据,每行有 m 个整数 Ci (0<=Ci<=12)代表这个格子上的宝物的价值
输出格式
  要求输出一个整数,表示正好取k个宝贝的行动方案数。该数字可能很大,输出它对 1000000007 取模的结果。
样例输入
2 2 2
1 2
2 1
样例输出
2
样例输入
2 3 2
1 2 3
2 1 5
样例输出
14
 

AC  code:


#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int mod=1000000007;

LL dp[55][55][15][15];//前两维对应地图,第3维为宝物个数,第4维为这些宝物的最大值
int map[55][55];
int n,m,k,num,maxvalue;

int main(){
    while(cin>>n>>m>>k){
        memset(dp,0,sizeof(dp));
        dp[1][1][0][0]=1;//初始化
        for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){cin>>map[i][j];map[i][j]++;}//避免编号为0
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                for(int num=0;num<=k;num++){//继承上左的情况
                    for(int maxvalue=0;maxvalue<=13;maxvalue++){
                        dp[i][j][num][maxvalue]+=dp[i-1][j][num][maxvalue];
                        dp[i][j][num][maxvalue]+=dp[i][j-1][num][maxvalue];
                        dp[i][j][num][maxvalue]%=mod;
                    }
                }
                for(int x=1;x<=k;x++){//拿起宝物后拥有x个宝物时的代码
                    for(int y=0;y<map[i][j];y++)dp[i][j][x][map[i][j]]+=dp[i][j][x-1][y];//拿起宝物
                    dp[i][j][x][map[i][j]]%=mod;
                }
            }
        }
        LL sum=0;
        for(int i=0;i<=13;i++)sum+=dp[n][m][k][i];
        cout<<sum%mod<<"\n";
    }
    return 0;
}


<think>嗯,用户问的是DFS和直接递推的区别,还有它们的适用场景对比。首先,我需要明确这两个概念。DFS是深度优先搜索,属于图遍历算法的一种,通常用递归者栈来实现。而直接递推可能指的是直接的递归方法,不一定是针对图结构的。 然后,我得想它们之间的主要差异。DFS通常用于遍历搜索图树的结构,而直接递推可能更多用于解决分治问题,比如斐波那契数列、阶乘计算等。结构差异方面,DFS需要维护访问状态,避免重复访问,而直接递推可能不需要,因为它可能处理的是没有环的结构,者问题本身的结构就不需要。 执行方式上,DFS是系统栈显式栈来管理调用,而直接递推可能完全依赖系统栈。空间开销的话,DFS如果用递归可能会有栈溢出的风险,特别是深度大的时候,而直接递推如果递归层次深也会有同样的问题。不过DFS有时候可以改用迭代方式避免这个问题。 适用场景方面,DFS适合图遍历、路径查找、连通性问题,而直接递推适合数学问题、分治、动态规划等。例如,DFS用于迷宫求解,而递推用于斐波那契数计算。 还要考虑用户可能的实际应用,比如他们可能在解决算法题时遇到选择DFS还是直接递归的情况。需要举例子说明,比如二叉树遍历用DFS,阶乘用递推。同时,引用中的资料提到DFS需要处理环的问题,而直接递推可能不涉及这些。 可能用户对两者的底层机制不太清楚,需要解释递归只是DFS的一种实现方式,而DFS本身是一种算法思想,可以用递归栈来实现。此外,性能优化方面,DFS可能需要剪枝,而递推可能需要注意重复计算,比如用记忆化优化。 总结下来,结构差异、执行方式、空间开销和应用场景是主要区别点。要确保回答清晰,对比明确,并且结合引用中的内容,比如引用[5]提到DFS的存储开销小,适用于图遍历,而引用[3]提到BFS适合最短路径,但这里比较的是DFS递推。 最后,生成相关问题时要围绕两者的区别和应用,比如问DFS在递归实现时的注意事项,递推在分治中的应用案例。</think>### 深度优先搜索(DFS)与直接递推的差异及适用场景对比 #### 一、核心差异分析 1. **算法目标与结构差异** - **DFS**:专门用于遍历搜索**图/树结构**,需处理顶点间的关系(如邻接表、邻接矩阵),需维护访问状态(颜色标记)避免重复访问[^5]。 - **直接递推**:通常用于解决**数学问题分治问题**(如斐波那契数列、阶乘计算),不依赖特定数据结构,仅通过递归调用自身分解问题。 2. **执行方式与空间开销** - **DFS**: - 显式隐式使用**栈结构**(递归调用依赖系统栈,迭代实现需手动维护栈)。 - 空间复杂度为$O(h)$($h$为图的最大深度),可能因递归过深导致栈溢出[^5]。 - **直接递推**: - 完全依赖**系统栈**,递归层次由问题规模决定。 - 若未优化(如尾递归记忆化),可能因重复计算导致指数级时间复杂度(如朴素斐波那契递归)。 3. **状态管理与回溯机制** - **DFS**:需记录已访问节点(如颜色标记),并在回溯时恢复状态(如迷宫问题中的路径撤销)[^4]。 - **直接递推**:通常无需回溯,仅通过参数传递状态,计算结果直接返回。 #### 二、适用场景对比 | **场景** | **DFS** | **直接递推** | |-------------------------|----------------------------------|-----------------------------| | **问题类型** | 图/树遍历、路径搜索、连通性判断 | 数学计算、分治、动态规划基础 | | **典型应用** | 迷宫求解、拓扑排序、无环图检测 | 阶乘、斐波那契数、汉诺塔问题 | | **数据结构依赖** | 必须基于图树的邻接关系 | 无需显式数据结构支持 | | **性能优化重点** | 剪枝、迭代替代递归 | 记忆化、尾递归优化 | #### 三、代码示例对比 **DFS实现(图遍历)** ```python def dfs(graph, node, visited): if node not in visited: visited.add(node) for neighbor in graph[node]: dfs(graph, neighbor, visited) ``` **直接递推(斐波那契数列)** ```python def fib(n): if n <= 1: return n return fib(n-1) + fib(n-2) ``` #### 四、关键区别总结 1. **问题领域**:DFS针对图结构,递推面向数学分治问题。 2. **状态管理**:DFS需显式处理访问状态和回溯,递推依赖参数传递。 3. **空间效率**:DFS可通过迭代优化栈深度,递推需依赖问题特性优化(如记忆化)[^3]。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林下的码路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值