题目链接
上体育课的时候,小蛮的老师经常带着同学们一起做游戏。这次,老师带着同学们一起做传球游戏。
游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球,每个同学可以把球传给自己左右的两个同学中的一个(左右任意),当老师再次吹哨子时,传球停止,此时,拿着球没传出去的那个同学就是败者,要给大家表演一个节目。
聪明的小蛮提出一个有趣的问题:有多少种不同的传球方法可以使得从小蛮手里开始传的球,传了m次以后,又回到小蛮手里。两种传球的方法被视作不同的方法,当且仅当这两种方法中,接到球的同学按接球顺序组成的序列是不同的。比如有3个同学1号、2号、3号,并假设小蛮为1号,球传了3次回到小蛮手里的方式有1->2->3->1和1->3->2->1,共2种。
输入描述
共一行,有两个用空格隔开的整数$n,m(3\leq n\leq 30,1\leq m\leq30)$。
输出描述
共一行,有一个整数,表示符合题意的方法数。
样例输入
样例输出
数据范围及提示
$40\%$的数据满足:$3\leq n\leq 30,1\leq m\leq 20$
$100\%$的数据满足:$3\leq n\leq 30$,$1\leq m\leq30$
思路
$dp[i][j]$表示第$i$次传球后在第$j$个人手上的方案数
那么$dp[i][j]$将由第$i$次传球的两个状态转移而来——$dp[i-1][j-1]$和$dp[i-1][j+1]$
转移方程为:$dp[i][j]=dp[i-1][j-1]+dp[i-1][j+1]$
要注意$n$个同学站成了一个圈,所以需要注意第$n$个人和第$1$个人旁边的两个人的编号
AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
|
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <math.h> #include <limits.h> #include <map> #include <stack> #include <queue> #include <vector> #include <set> #include <string> #include <time.h> #define ll long long #define ull unsigned long long #define ms(a,b) memset(a,b,sizeof(a)) #define pi acos(-1.0) #define INF 0x7f7f7f7f #define lson o<<1 #define rson o<<1|1 #define bug cout<<"-------------"<<endl #define debug(...) cerr<<"["<<#__VA_ARGS__":"<<(__VA_ARGS__)<<"]"<<"\n" const double E=exp(1); const int maxn=1e3+10; const int mod=1e9+7; using namespace std; int dp[maxn][maxn]; int main(int argc, char const *argv[]) { ios::sync_with_stdio(false); int n,m; cin>>n>>m; dp[1][n]=dp[1][2]=1; for(int i=2;i<=m;i++) { for(int j=1;j<=n;j++) { int a,b; if(j==1) a=dp[i-1][n]; else a=dp[i-1][j-1]; if(j==n) b=dp[i-1][1]; else b=dp[i-1][j+1]; dp[i][j]=a+b; } } cout<<dp[m][1]<<endl; return 0; }
|