传球游戏【递推】

题目描述

上体育课的时候,小蛮的老师经常带着同学们一起做游戏。这次,老师带着同学们一起做传球游戏。

游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球,每个同学可以把球传给自己左右的两个同学中的一个(左右任意),当老师再次吹哨子时,传球停止,此时,拿着球没有传出去的那个同学就是败者,要给大家表演一个节目。

聪明的小蛮提出一个有趣的问题:有多少种不同的传球方法可以使得从小蛮手里开始传的球,传了m次以后,又回到小蛮手里。两种传球方法被视作不同的方法,当且仅当这两种方法中,接到球的同学按接球顺序组成的序列是不同的。比如有三个同学1号、2号、3号,并假设小蛮为1号,球传了3次回到小蛮手里的方式有1->2->3->1和1->3->2->1,共2种。

输入输出格式

输入格式:
输入文件ball.in共一行,有两个用空格隔开的整数n,m(3<=n<=30,1<=m<=30)。

输出格式:
输出文件ball.out共一行,有一个整数,表示符合题意的方法数。

输入输出样例

输入样例#1: 复制
3 3
输出样例#1: 复制
2

分析:这道题我想大家对于状态转移方程可以很容易想出来了,设f【x】【y】表示传y次传到第x个人(特别地,由于是圆圈所以这里的第n个人设置为0号,方便%)的方法,那么f【x】【y】=f【(x-1+n)%n】【y-1】+f【(x+1+n)%n】【y-1】(这个方程就不用解释了吧,很容易理解的)(这里加个n是防止x-1变为负数)。想出来了之后,怎么去推这个f【(x-1+n)%n】【y-1】+f【(x+1+n)%n】【y-1】呢?我们要推这个,就要想:f【(x-1+n)%n】【y-1】=f【(x-2+n)%n】【y-2】+f【(x+n)%n】【y-2】。那么怎么去推这个f【(x-2+n)%n】【y-2】+f【(x+n)%n】【y-2】?…最后,我们发现,这跟递归非常想,立马联想到记忆化搜索,看了一下数据范围:只要程序不错,这道题完全行得通!

#include<bits/stdc++.h>
using namespace std;
int f[31][31];
int n,m;
inline int read()//读入优化,不会的读者可以直接用scanf 
{
    int f=1,x=0;
    char s=getchar();
    while(s<'0'||s>'9')
    {
        if(s=='-')
        {
            f=-f;
        }
        s=getchar();
    }
    while(s>='0'&&s<='9')
    {
        x=x*10+s-48;
        s=getchar();
    }
    return x*f;
}
int dfs(int x,int y)
{
    if(y==1&&(x==0||x==2))//从1号开始传起,传一次只能传给0号和2号 
    {
        return 1;//只有一种方法 
    }
    else if(y==1)//如果不是 0号和2号 且传球次数只有1次了,那么肯定行不通了,返回0 
    {
        return 0;
    }
    else if(f[x][y]!=-1)//如果这个结果已经被搜索过了,直接返回 
    {
        return f[x][y];
    }
    else
    {
        f[x][y]=dfs((x-1+n)%n,y-1)+dfs((x+1+n)%n,y-1);//没有的话进行递归 
        return f[x][y];//返回 
    }
}
int main()
{
    n=read(),m=read();
    memset(f,-1,sizeof(f));//先全部初始化为-1,因为f【x】【y】的值可能为0 
    printf("%d",dfs(1,m));//开始递归 
    return 0;
}

另外,这道题如果不用记忆华搜索直接递归会不会超时,我也没试过,有兴趣的读者可以自己尝试一下,谢谢各位

在解决传球游戏的问题时,你可以考虑使用两种常见的优化策略,例如广度优先搜索(BFS)和动态规划(DP)。以下是针对这两个算法的简要说明: 1. **广度优先搜索 (BFS)**: - 算法难度级别:入门到中级,对于熟悉图形算法的学生来说相对容易理解。 - 时间复杂度:在传球游戏中,如果树状结构不是太深(深度不大于N),BFS通常有O(N+M)的时间复杂度,其中N是节点数,M是边数。这是因为遍历每层都需要一次,而最坏的情况下,可能是所有节点都位于一层。 - 库:主要依赖于标准库中的队列数据结构,如`std::queue`,以及可能用于表示图的数据结构如邻接表。 ```cpp #include <iostream> #include <queue> // 使用邻接列表或其他数据结构存储传球图 std::vector<int> graph[N]; bool bfs(int start, int end) { std::queue<int> q; q.push(start); visited[start] = true; while (!q.empty()) { int node = q.front(); q.pop(); if (node == end) return true; // 找到了目标 for (int neighbor : graph[node]) { if (!visited[neighbor]) { visited[neighbor] = true; q.push(neighbor); } } } return false; } ``` 2. **动态规划 (DP)**: - 算法难度级别:中级到高级,涉及状态转移方程和递推思想。 - 时间复杂度:如果你将传球看作是从一个人手中传递给另一个人的序列决策问题,那么可以使用二维数组记录状态,时间复杂度是O(N^2),N是传球次数。更高效的解法可能通过记忆化搜索降低至O(N log N)或更低。 - 库:主要依赖于基本的数值计算和内存管理,不需要特定的库。 ```cpp bool dp[100][100]; // 假设最多100次传球 int solve(int player, int target, int passes) { if (passes == 0 || dp[player][target] != -1) return dp[player][target]; // 动态规划核心部分 for (int i = 1; i <= passes; ++i) { if (bfs(player, i)) { // 判断能否通过i次传球达到target dp[player][target] |= solve(i, target, passes - i); } } return dp[player][target]; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值