题目:https://www.luogu.org/problemnew/show/P1057
题意:
n个人围成一个圈,传球只能传给左边或是右边。
从第一个人开始传起,经过m次之后回到第一个人的传球方案有多少种。
思路:
发现有的时候dp的转移方程可以通过写递归得到。把递归给变成dp
用$dp[i][j]$表示第$j$号开始传$i$次回到$j$的方案数。很容易想到,第$i$次回到$j$时,一定是$j-1$或是$j+1$传回来的。
所以可以得到$dp[i][j] = dp[i-1][j-1]+dp[i-1][j+1]$
初始时是$dp[0][0] = 1$,终态是$dp[m][0]$
要注意因为是一个圈,所以我们用%来处理。为避免负数,$-1$的时候要$+n$
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<map> 4 #include<set> 5 #include<iostream> 6 #include<cstring> 7 #include<algorithm> 8 #include<vector> 9 #include<cmath> 10 #include<queue> 11 12 #define inf 0x7f7f7f7f 13 using namespace std; 14 typedef long long LL; 15 typedef pair<int, int> pr; 16 17 int n, m; 18 19 int dp[35][35]; 20 //dp[i][j]表示传i次回到j的方案数 21 //dp[i][j] = dp[i-1][j-1] + dp[i-1][j+1] 22 23 //int dfs(int x, int id) 24 //{ 25 // if(dp[x][id])return dp[x][id]; 26 // if(x == 0){ 27 // return 1; 28 // } 29 // int ans = 0; 30 // ans += dfs(x - 1, (id + 1) % n); 31 // ans += dfs(x - 1, (id - 1) % n); 32 // dp[x][id] = ans; 33 // return ans; 34 //} 35 36 37 int main() 38 { 39 scanf("%d%d", &n, &m); 40 dp[0][0] = 1; 41 for(int i = 1; i <= m; i++){ 42 for(int j = 0; j < n; j++){ 43 dp[i][j] = dp[i - 1][(j - 1 + n) % n] + dp[i - 1][(j + 1) % n]; 44 } 45 } 46 printf("%d ", dp[m][0]); 47 48 return 0; 49 }