[NOIP 2008] 传球游戏

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个人手上的方案数,再由题意可知,一个人手上的球只能由旁边的人传来,也就是左边和右边,于是我们就可以列出方程:

                ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        \large f_i_j=f_i{_-{}_1}_j{_-{}_1}+f_i{_-{}_1}_j{_+{}_1}

即为第i次传到第j个人的方案数等于他左边的加上右边的

当然,除此之外还有特殊情况

这是一个环,而如果我们只有这一个方程就没法处理第1和第n个人,所以我们还得加个特判,就是判断当前是否为第1或第n个人,如果是,也同理,只不过第一个人左边是n右边是2,第n个人右边是1,左边是n-1,于是可以列出方程:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        \large N:f_i_,{_j}=f{_i{_-{}_1}}_,{_1}+f{_i{_-{}_1}}_,{_n{_-{}_1}}

和:

                                                \large 1:f_i_,{_j}=f{_i{_-{}_1}_,}{_j_+{_1}}+f{_i{_-{}_1}_,}{_n}

最后输出\large f_1_,{_m}即可,也就是第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;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值