蓝桥杯备赛:记忆化搜索和return

14年省数的题目:

1.地宫取宝 - 蓝桥云课

我每次都用dfs写,然后写不对(笑)标答是记忆化搜索

先附上标答:

#include <bits/stdc++.h>
using namespace std;
int n,m,k;
const int mod=1e9+7;
typedef long long ll;
int c[55][55];
long long ans;
int dp[55][55][13][13];//到(x,y)开始走的时候,拿了多少个,现在手里最大值是多少
bool istrue(int x,int y)
{
  return x<=n&&y<=m;
}
ll dfs(int x,int y,int cnt,int mx)
{
  ll res=0;
  if(!istrue(x,y))
  return 0;
  if(x==n&&y==m&&cnt==k)//到达终点且不需要最后一件
  return dp[x][y][cnt][mx]=res+1;
  if(dp[x][y][cnt][mx]!=-1)
  return dp[x][y][cnt][mx];//计算过了
  if(x==n&&y==m&&cnt==k-1&&c[n][m]>mx)//到达终点且需要最后一件
  return dp[x][y][cnt+1][c[n][m]]=res+1;

  //没到终点
  if(c[x][y]>mx)
  {
    res=(res+dfs(x,y+1,cnt+1,c[x][y]))%mod;//拿了向下走
    res=(res+dfs(x+1,y,cnt+1,c[x][y]))%mod;//拿了向右走
  }
  res=(res+dfs(x,y+1,cnt,mx))%mod;//不拿直接走
  res=(res+dfs(x+1,y,cnt,mx))%mod;
  return dp[x][y][cnt][mx]=res;
}
int main()
{
  cin>>n>>m>>k;
  for(int i=1;i<=n;i++)
  {
    for(int j=1;j<=m;j++)
    {cin>>c[i][j];
    c[i][j]++;//防止全为0
    }
  }
  memset(dp,-1,sizeof(dp));
  cout<<dfs(1,1,0,0)%mod;
  return 0;
}

Q1:能否使用纯dfs?

对于小规模数据(如n, m ≤ 10),可以尝试纯DFS,但时间复杂度极高(指数级)。对于题目中的规模(n, m = 55),必须使用记忆化优化。

但我还是问了ds如果用纯dfs的代码能写吗,能写,只能过50%。

如下:

#include <bits/stdc++.h>
using namespace std;
int n, m, k, p = 1e9 + 7;
int a[55][55];

long long dfs(int x, int y, int mx, int cnt) {
    if (x == n && y == m) return cnt == k;
    long long res = 0;
    for (int i = 0; i < 2; i++) { // 向下或向右
        int nx = x + (i == 0 ? 1 : 0);
        int ny = y + (i == 1 ? 1 : 0);
        if (nx < 1 || ny < 1 || nx > n || ny > m) continue;
        // 拿当前宝物(如果条件允许)
        if (a[nx][ny] > mx && cnt < k) 
            res += dfs(nx, ny, a[nx][ny], cnt + 1);
        // 不拿当前宝物
        res += dfs(nx, ny, mx, cnt);
        res %= p;
    }
    return res;
}

int main() {
    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]++; // 确保价值最小为1
        }
    cout << (dfs(1, 1, 0, 0) + dfs(1, 1, a[1][1], 1)) % p;
    return 0;
}

Q2:记忆化搜索和动态规划是一样的吗?

 不一样。(具体哪不一样我还说不出来sosss)

特性记忆化搜索(自顶向下)动态规划(自底向上)
实现方式递归 + 缓存迭代填表
计算顺序按需计算,仅计算必要子问题预先计算所有可能子问题
代码直观性更贴近问题逻辑,易理解需设计状态转移顺序,较复杂
空间优化潜力可能只需缓存部分状态通常需存储完整状态表

就这题来说,记忆化搜索很像dfs的思想+动态规划的方法(个人感觉哈求指正~~)

特别是dp数组的定义。

int dp[55][55][13][13];//到(x,y)开始走的时候,拿了多少个,现在手里最大值是多少

Q3:return dp[x][y][cnt][mx]=res; 如何理解?

在C++中,return 本身并不是运算符,而是一个语句。return 语句后的表达式会被完整求值,包括其中的运算符优先级。

该语句将 res 的值赋给 dp[x][y][cnt][m](记忆化),并返回res的值。

等价于:

dp[x][y][cnt][m] = res;  // 先赋值
return res;               // 再返回 res 的值

ps:这是第一次遇到记忆化搜索的题目,感觉太容易混淆了,还是练的太少题写的太少(叹气)

一起加油!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值