暴搜代码:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int n, m, cnt;
const int N = 1e3 + 1;
int dx[2] = {1, 0}, dy[2] = {0, 1};
void dfs (int x, int y)
{
if (x == n && y == m) {
cnt ++;
return;
}
for (int i=0; i < 2; i ++)
{
int a = x + dx[i], b = y + dy[i];
if (a>n || b>m || (a%2==0 && b%2==0)) continue;
dfs (a, b);
}
}
int main()
{
cin >> n >> m;
if (n%2==0 && m%2==0){
cnt = 0;
}
else dfs (1, 1);
cout << cnt << endl;
return 0;
}
动态规划:
下图是:动态规划打表图,很明显可以看出其中每个格子的方案数等于上面格子的方案数 + 左边格子的方案数。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 40;
int f[N][N]; //f[i][j]表示从(1,1)走到(i,j)的方案数!
int n, m;
//思考:(i,j)这个点只能由(i-1, j) 或者 (i,j-1)这个点转移过来
// f[i][j] = f[i-1][j]; f[i][j] = f[i][j-1]; 即为转化的可能性!
int main()
{
cin >> n >> m;
//初始化所有边界的问题!
for (int i=1; i <= n; i ++)
f[i][1] = 1;
for (int j=1; j <= m; j ++)
f[1][j] = 1;
for (int i=2; i <= n; i ++)
for (int j=2; j <= m; j ++)
if (i&1 || j&1)
f[i][j] = f[i-1][j] + f[i][j-1];
cout << f[n][m] << endl;
return 0;
}
记忆化搜索:
从第一个格子开始搜索!
凡是搜索过的格子就给它标注一下,然后下次再遇到这个格子的时候,说明这个格子之前已经走过了,无论它是否走得到终点,它之前走的时候,答案都均已被记录下来了。再走一遍也是同样的效果,没有实际意义!
回溯时标记更新!!!
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 40;
int f[N][N]; //f[i][j]:表示该点是否已经走过了!
int n, m;
int dfs (int x, int y)
{
if (x&1 || y&1)
{
if (f[x][y]) return f[x][y];
if (x < n) f[x][y] += dfs (x+1, y);
if (y < m) f[x][y] += dfs (x, y+1);
}
return f[x][y];
}
int main()
{
cin >> n >> m;
f[n][m] = n&1 || m&1;
cout << dfs (1, 1);
return 0;
}```