一个环,有n个点, 问从0点出发,经过k步回到原点有多少种方法

来源:互联网 发布:数据工资保密协议 编辑:程序博客网 时间:2024/04/30 18:04

 一个环,有n个点, 每次只能走一步, 问从原点0出发,经过k步回到原点有多少种方法?

                     0

                  /         \

                 /           \

              2  ---------1    


现在把环上的点编号为0 到 n-1, 即从0点出发,再回到0点有多少种方法?

我们可以想到,再回到0点可以从右面回来,也可以从左面回来,即先到达旁边的一个点,看看有多少回来的方法即可。所以运用动态规划的思想,我们可以写出递推式如下:

d(k, j) = d(k-1, j-1) + d(k-1, j+1);

d(k, j)表示从点j 走k步到达原点0的方法数, 因此可以转化为他相邻的点经过k-1步回到原点的问题,这样将问题的规模缩小。由于是环的问题, j-1, j+1可能会超出 0到n-1的范围,因此,我们将递推式改成如下:

 d(k, j) = d(k-1, (j-1+n)%n) + d(k-1, (j+1)%n);

因为问题从走k步转化为走k-1步的问题,所以在写程序的时候我们就按照k从0开始递增的循环写,这样当计算第k步的时候可以直接使用k-1步的结果。

实例如下, n = 3, k = 4

按照k增大计算

 012k=0100k=1011k=2211k=3233k=4655

因为计算第k步只与第k-1步的值有关,因此可以使用两行的数组来存储。代码如下:



/** * 一个圆环, 有n个点, 从0出发,每次只能走一步,问走k步,有多少种方法可以走回来 */#define N 100int get_step_num(int n, int k){if (n==1){return 1;}if (n==2){if (k%2==0)return 1;else return 0;}int arr[2][N] = {0};int flag = 1, i = 0, j = 0;arr[0][0] = 1;for (i=1; i<n; i++){arr[0][i] = 0;}// j is the current stepfor (j=1; j<=k; j++){for (i=0; i<n; i++){arr[flag][i] = arr[!flag][(i-1+n)%n] + arr[!flag][(i+1)%n];}flag = !flag;}return arr[!flag][0];}int main(){int n, k;printf("Please input the number n and the step k:\n");scanf("%d%d", &n, &k);printf("%d\n", get_step_num(n, k));return 0;}