一.dfs
从(1,1)的位置上走到(n,m)位置上,只能右走或者下走并且不能走行和列是偶数的各子
那么第一眼想到的是用dfs来写:
首先构建一个二维数组来构造一个坐标系(数组内不用填充数据,只要初始化为0就行了,因为用不到里面的数据,只用到了行和列的序号)
其次就要注意边界的问题:
- 如果在当前dfs里x==n&&y==m的话就证明到了终点,那么返回一种情况
- 如果在当前dfs里x >n||y>m的话就证明x,y有一个或者两个都超过了边界,那么就要返回到上一次的递归状态,重新寻找路径
- 如果在当前dfs里x%2==0&&y%2==0,就证明走到了行和列都是偶数的格子上面,那么这种情况也是不能要的,同样要返回上一次递归的状态,重新寻找路径
判断完边界的情况后就可以进行递归了:dfs(x,y + 1),dfs(x + 1,y);一个是向右走,一个是向下走(上面三种的判断情况在写代码的时候部分先后顺序的,但递归的代码一定要在最后写
因为你怎么还么判断边界情况呢,怎么就往下走了,不要辣么着急)
但不管是向下走还是向右都会返回一种达到的情况的,那么就要将成功返回的情况加起来:cnt(答案) = dfs(x,y + 1) + dfs(x + 1,y);
下面是代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 31,M = 31;
int a[N][M];
int n,m;
int cnt;
int dfs(int i, int j)
{
if(i>n||j>m)
return 0;
if(i == n&&j == m)
return 1;
if(i%2==0&&j%2==0)
return 0;
cnt = dfs(i + 1,j) + dfs(i,j + 1);
return cnt;
}
int main() {
scanf("%d%d",&n,&m);
// 输出路径数量
printf("%d",dfs(1,1));
return 0;
}
二.记忆化搜索
写出来了,也能够过样例,但最后一个样例超时了,怎么办???
那就用《记忆化搜索》:
还是上面的一个数组,坐标,当进行dfs的时候可能会发生比如向下走的情况走到了op这个点,而向右走的经过若干存在也走到了op这个点,而这个点已经走过了,但还会再走一边没这样的的话就会浪费时间吗,而记忆化搜索就是将遇见已经走过的点直接返回op这个点的计算结果,
再原来是的基础是加一个记忆化数组merey,用来是存储没走过的点的计算状态,如果遇见走过的点的话就直接返回以前的计算结果:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 31,M = 31;
int a[N][M];
int n,m;
int cnt;
int merey[N][N];
int dfs(int i, int j)
{
if(i>n||j>m)
return 0;
if(i == n&&j == m)
return 1;
if(i%2==0&&j%2==0)
return 0;
if(merey[i][j]!=-1)
//当这个点走过的话就直接返回计算状态
{
return merey[i][j];
}
cnt = dfs(i + 1,j) + dfs(i,j + 1);
return merey[i][j] = cnt;//存储的是每一个点的计算状态;
}
int main() {
cin >> n >> m;
memset(merey,-1,sizeof merey);
cout << dfs(1, 1);
return 0;
}
将记忆数组输出:
-1的地方是没走到的,而1的地方是走过的,由于递归是从最低层一步一步但会回来的,所以最后一次返回到的是(1,1)这个点上的;
三.动态规划
集合:f[i][j]:从(1,1)到(i,j)的方案数量
属性:数量
状态转移:有两种情况要不从做左边来,要不上面来:
方程:f[i][j] = f[I -1 ][j] + f[i][j -1 ]’
f[1][1] = 1,因为(1,1)到(1,1)只有直自己:
#include<bits/stdc++.h>
using namespace std;
const int N = 35;
int f[N+10][N+10];
int n,m;
void init(){
f[1][1]=1;
for(int i=1;i<=N;i++){
for(int j=1;j<=N;j++){
if(i==1&&j==1) continue;
if(i%2==0&&j%2==0) continue;
else f[i][j]=f[i-1][j]+f[i][j-1];
}
}
}
int main(){
cin>>n>>m;
init();
cout<<f[n][m]<<endl;
return 0;
还可以压缩一维的但本蒟蒻不会:具体可以看大佬:AcWing 2067. 走方格 - AcWing
本篇题解是为了自己能够加深印象方便以后理解的,如果又不好的地方就请及时告诉蒟蒻,如果能帮助到其他人就更好了
若有侵权,立删