Openjudge9271:奶牛散步(递推问题)

从一个无限大的矩阵的中心点出发,一步只能向右走、向上走或向左走。恰好走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;
}

 

posted @ 2021-04-27 20:26  Mint-hexagram  阅读(628)  评论(0编辑  收藏  举报