CSP历年复赛题-P1057 [NOIP2008 普及组] 传球游戏

原题链接:https://www.luogu.com.cn/problem/P1057

题意解读:n个人围一圈,从1开始传球m次,每次可以往左或右传,计算球再次传给1的方案数。

解题思路:

求方案数,通常就是DP问题,此题DP状态并不难想,如果实在不会,也可以通过DFS暴搜得部分分。

1、DFS

60分代码:

#include <bits/stdc++.h>
using namespace std;

int n, m, ans;

//经过cnt次传球到x
void dfs(int cnt, int x)
{
    if(cnt == m)
    {
        if(x == 1) ans++;
        return;
    }

    int next = x + 1; //下一次传给x+1
    if(next > n) next = 1;
    dfs(cnt + 1, next);

    int pre = x - 1; //下一次传给x-1
    if(pre < 1) pre = n;
    dfs(cnt + 1, pre);
}

int main()
{
    cin >> n >> m;
    dfs(0, 1);
    cout << ans;

    return 0;
}

2、动态规划

状态表示:

  设dp[i][j]表示经过i次球从1传到j的方案数

状态转移:

  考虑i-1次的情况,i-1传球可以传到j-1,也可以传到j+1,

  因此可以得到dp[i][j] = dp[i-1][j-1] + dp[i-1][j+1]

  但是需要考虑j的取值,当j == 1时 j - 1替换为n,当j == n时,j + 1替换为1

初始化:

  dp[0][1] = 1,0次传球到1的方案是1

结果:

  dp[m][1],m次传球到1的方案数

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 35;

int n, m;
int dp[N][N]; //dp[i][j]表示经过i次球从1传到j的方案数

int main()
{
    cin >> n >> m;
    dp[0][1] = 1;
    for(int i = 1; i <= m; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            if(j == 1) dp[i][j] += dp[i-1][n];
            else dp[i][j] += dp[i-1][j-1];

            if(j == n) dp[i][j] += dp[i-1][1];
            else dp[i][j] += dp[i-1][j+1];
        }
    }
    cout << dp[m][1];

    return 0;
}

 

posted @ 2024-05-27 17:58  五月江城  阅读(46)  评论(0编辑  收藏  举报