传球游戏【递推】

题目描述

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

游戏规则是这样的: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;
}

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

posted @ 2018-03-16 19:07  最爱丁珰  阅读(51)  评论(0编辑  收藏  举报