圆环回原点问题

 

问题描述

一个环上有10个点,编号为0-9,从0点出发,每步可以顺时针到下一个点,也可以逆时针到上一个点,求:经过n步又

回到0点有多少种不同的走法
image
举例:

如果n=1,则从0出发只能到1或者9,不可能回到0,共0种走法

如果n=2,则从0出发有4条路径:0->1->2, 0->1->0, 0->9->8, 0->9->0,其中有两条回到了0点,故一共有2种走法
  •  

思路(动态规划)

  • 我们可以想到,再回到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步的结果。

go实现

//n 代表点的个数,k代表bushu
func GetSteps(n int, k int) int {
	if n == 0 {
		return 1
	}
	if n == 2 {
		if n%2 == 0 {
			return 1
		} else {
			return 0
		}
	}
	var dp [100][100]int

	dp[0][0] = 1
	for i := 1; i < n; i++ {
		dp[0][i] = 0
	}
	for j := 1; j <= k; j++ {
		for i := 0; i < n; i++ {
			dp[j][i] = dp[j-1][(i-1+n)%n] + dp[j-1][(i+1)%n]
		}
	}
	return dp[k][0]
}

C++实现

/**
 * 一个圆环, 有n个点, 从0出发,每次只能走一步,问走k步,有多少种方法可以走回来
 */
 
#define N 100
 
int 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 step
    for (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;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值