一、题目描述
上体育课的时候,小蛮的老师经常带着同学们一起做游戏。这次,老师带着同学们一起做传球游戏。
游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球,每个同学可以把球传给自己左右的两个同学中的一个(左右任意),当老师再次吹哨子时,传球停止,此时,拿着球没传出去的那个同学就是败者,要给大家表演一个节目。
聪明的小蛮提出一个有趣的问题:有多少种不同的传球方法可以使得从小蛮手里开始传的球,传了m次以后,又回到小蛮手里。两种传球的方法被视作不同的方 法,当且仅当这两种方法中,接到球的同学按接球顺序组成的序列是不同的。比如有3个同学1号、2号、3号,并假设小蛮为1号,球传了3次回到小蛮手里的方 式有1-> 2-> 3-> 1和1-> 3-> 2-> 1,共2种。
1.输入格式
共一行,有两个用空格隔开的整数n,m(3< =n< =30,1< =m< =30)。
数据规模和约定
100%的数据满足:3< =n< =30,1< =m< =30
2.输出格式
t共一行,有一个整数,表示符合题意的方法数。
二、样例
样例输入:
3 3
样例输出:
2
二、样例分析
1.思路分析
首先呢模拟一下流程,这里有两种刚开始思考的思路
第一就是利用递归和嵌套思想。本题呢可以这样想,就是需要找出中间的传递者,比如:以题目为例就是1,——,——,1我需要做的就是向里面去填数,这里最简单的方法就是把要填进去数的相邻两位都填进去判断是否可以。具体的实现就是:第一个空我可以拿2进去,也可以是3,这个时候我先取2,然后第二个空就找和2相邻的继续去填,这个空的个数就是m-1,如果在最后一步不是满足的话可以利用 return 0返回到上一步,如果还不行就继续返回到上一步。
这里可以去尝试一些一下,代码比较繁杂,运行时间也比较多。
第二就是去计算传递到每个同学的可能,这里你要明白一点就是:有几种可能传递到第一位同学,那么这个就是我们所要的。
思考一下怎么计算,这里要想到一点就是传递的次数可能大于人数。那么我们开始,首先在没有传递之前每个人都是0 左边是编号右边是可能的次数(以题目为例子)
1,0 — 2,0 —3,0 — 4,0
1,0 — 2,1— 3,0—4,1 (第一次传递的可能只能是2号和4号)
1,2—2,1— 3,1—4,1(第二次2号可以给1,3四号可以给1,3,这里注意可能次数是累加的,这里一定要想明白)
所以这里就需要利用到二维数组来储存号码和可能的次数。
2.代码实现
代码如下:
#include <iostream>
using namespace std;
int n;//注意定义位置
int main() {
int fun(int);
int m, i, j, f[31][31] = {0};
cin >> n >> m ;
f[1][2] = f[1][n] = 1; //第1次传球,1号只可能传给2号或n号
for (i = 2; i <= m; i++) //传球次数
for (j = 1; j <= n; j++) //同学传递个数
f[i][j] = f[i - 1][fun(j - 1)] + f[i - 1][fun(j + 1)];//可能次数相加
cout << f[m][1]; //第m次后传给1号的可能
return 0;
}
int fun(int x) { //编号修改函数
if (x < 1)
return x + n; //编号减少到0时,传到编号n
if (x > n)
return x - n; //编号增加到n+1时,传到编号1
return x;
}
这个编码修改函数呢也可以利用循环数组对n求余的操作来实现。
总结
思路有很多,便捷的才好
今日文案:愿山河无恙,所念皆有回响