问题描述
一个环上有10个点,编号为0-9,从0点出发,每步可以顺时针到下一个点,也可以逆时针到上一个点,求:经过n步又
回到0点有多少种不同的走法
举例:
如果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;
}