从一个无限大的矩阵的中心点出发,一步只能向右走、向上走或向左走。恰好走N步且不经过已走的点
共有多少种走法?
输入
一个数字,代表N,N<=1000
输出
方案数sum
样例 : 输入 2 输出 7
注:openjudge日常坑人(指题面没说要取模但是因为数据规模太大所以要把结果%12345
分析:
《1》可以发现,这道题的输入只有步数n,没有其他信息,所以很明显对于每个n来说,方案数是恒定不变的,因此是一个递推(dp的一种
《2》状态转移的分析:
先看道题的状态有几个:第一组是已经走的步数和走到的位置
第二组是已经走的步数和这一步走的方向
很明显如果用第一组状态转移方程,那么就发现走到的位置不是一定的(特别多),因此统计总数就非常的复杂,(而且枚举位置非常复杂),
因此肯定不能选择这种思路(更何况开dp[1005][1005][1005]连空间都爆了)
用第二种,诶,就能发现它非常简单(O(N)), 就能解决问题,只要在f[i][4]存一下方案总数就可以
《3》可以写出状态转移方程
2 <= i <= n
1表示向右
2表示向左
3表示向上
初始化f[1][1] = 1;
f[1][2] = 1;
f[1][3] = 1;
f[1][4] =3;
f[i][1] = sum(f[i - 1][1],f[i - 1][3])
f[i][2] = sum(f[i - 1][2],f[i - 1][3])
f[i][3] = sum(f[i - 1][1],f[i - 1][2],f[i - 1][3])
f[i][4] = sum(f[i][1],f[i][2],f[i][3])
《4》可以通过选择当前情况由那些情况转移而来(即选择是从哪个方向走来的)来避免重复走已经走过的点
而不是再开一个数组判断某个点是否走过
AC代码
#include<algorithm> #include<cstdio> using namespace std; int n, f[1005][5]; int main() { scanf("%d", &n); f[1][1] = 1; f[1][2] = 1; f[1][3] = 1; f[1][4] = 3; for(int i = 2;i <= n;i++) { f[i][1] = (f[i - 1][1] + f[i - 1][3]) % 12345; f[i][2] = (f[i - 1][2] + f[i - 1][3]) % 12345; f[i][3] = (f[i - 1][1] + f[i - 1][2] + f[i - 1][3])%12345; f[i][4] = (f[i][1] + f[i][2] + f[i][3])%12345; } printf("%d", f[n][4]); return 0; }
原文:https://www.cnblogs.com/mint-hexagram/p/14710752.html