Description:
上体育课的时候,小蛮的老师经常带着同学们一起做游戏。这次,老师带着同学们一起做传球游戏。
游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球,每个同学可以把球传给自己左右的两个同学中的一个(左右任意),当老师再次吹哨子时,传球停止,此时,拿着球没传出去的那个同学就是败者,要给大家表演一个节目。
聪明的小蛮提出一个有趣的问题:有多少种不同的传球方法可以使得从小蛮手里开始传的球,传了m次以后,又回到小蛮手里。两种传球的方法被视作不同的方法,当且仅当这两种方法中,接到球的同学按接球顺序组成的序列是不同的。比如有3个同学1号、2号、3号,并假设小蛮为1号,球传了3次回到小蛮手里的方式有1->2->3->1和1->3->2->1,共2种。
Input:
输入文件ball.in共一行,有两个用空格隔开的整数n,m(3<=n<=30,1<=m<=30)。
Output:
输出文件ball.out共一行,有一个整数,表示符合题意的方法数。
Sample Input:
3 3
Sample Output:
2
其实这就是一道很简单的DP,我们可以令f[i,j]为第i次传球到第j个人手上的方案数,再由题意可知,一个人手上的球只能由旁边的人传来,也就是左边和右边,于是我们就可以列出方程:
即为第i次传到第j个人的方案数等于他左边的加上右边的
当然,除此之外还有特殊情况
这是一个环,而如果我们只有这一个方程就没法处理第1和第n个人,所以我们还得加个特判,就是判断当前是否为第1或第n个人,如果是,也同理,只不过第一个人左边是n右边是2,第n个人右边是1,左边是n-1,于是可以列出方程:
和:
最后输出即可,也就是第m次回到第1个人的方案数.
基本也讲完了,其实也不难,稍加思考即可
接下来放出代码:
#include <iostream>
#include <stdio.h>
#include <iomanip>
#include <algorithm>
#include <math.h>
#define r register
#define N 1000000
#define o __attribute__((optimize("-O3")))
using namespace std;
const int M = 1000;
int n, m, f[M][M];
o int main () {
freopen("ball.in", "r", stdin);
freopen("ball.out", "w", stdout);
scanf("%d %d", &n, &m);
f[1][0] = 1;
for (r int j = 1; j <= m; ++ j) {
for (r int i = 1; i <= n; ++ i) {
if (i == 1) {
f[i][j] = f[n][j - 1] + f[2][j - 1];
} else if (i == n) {
f[i][j] = f[i - 1][j - 1] + f[1][j - 1];
} else {
f[i][j] = f[i - 1][j - 1] + f[i + 1][j - 1];
}
}
}
printf("%d", f[1][m]);
return 0;
}