14年省数的题目:
我每次都用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:这是第一次遇到记忆化搜索的题目,感觉太容易混淆了,还是练的太少题写的太少(叹气)
一起加油!!!