题解 P1057 【传球游戏】

这道题我想大家对于状态转移方程可以很容易想出来了,设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 18:59  最爱丁珰  阅读(24)  评论(0编辑  收藏  举报