zoj2290 Game----博弈 打表找规律

来源:互联网 发布:angew在哪个数据库 编辑:程序博客网 时间:2024/05/29 11:54
Game

Time Limit: 2 Seconds      Memory Limit: 65536 KB

Two players(A and B) take turns to take stones form a heap of N stones.

There are some rules:
1.A always takes first. He can take arbitrary number of stones but not all of them.
2.The number of the one who will take should less than or equal the twice of the other one taken last time. But must more than one or one.
3.The one who take take the last one stone is the winner.
4.The two players are clever enough, they can make the best choice.

Input

Every test case has only one line with one integer N(2 <= N <= 100000000), the numbers of the stones.

Output

If A will lose output "lose"

If A can win,output the numbers A should take at the first time. If there are more ways to make A win, output the smallest one.

Sample Input

4

Sample Output

1

 

题意:有一堆个数为n的石子,两个人,第一个可以拿任意石子,但不能全部拿走,下一个人开始拿的石子必须小于或者等于上一个人拿的石子的2倍。

先前在杭电做过这题,已经知道必败点是斐波那契数列了,做这题的时候特地打了一个表验证了一下。

做这种题的时候,如果数据量很大的时候,显然我们必须通过打表找规律。

然后就是第二问了,如果先手必胜,我们要输出先手第一次最少拿走多少石子。

一开始我想的是,先手拿完石子后,只要给对方留下的石子是斐波那契数列中的数值就可以,所以我将最接近并且小于n的那个斐波那契数求出来,用n减去那个数的值作为答案,但是这种想法其实是错误的!因为求出的数未必是最小的,还有可能很大很大!

假设我求出的那个斐波那契数是x,显然我们要把对手逼到那个数的状态,但不是意味着我们要通过第一步就把对手逼到这个状态,这样求出来的数未必是最小的。

为了使得对手到达x这个状态,那么目前就只剩n-x颗石头了,我们该怎么取石子呢?

发现没有,这其实是个递归的过程,而递归的出口就是n-x==某个斐波那契数!

打表代码:

#include<iostream>#include<cstdlib>#include<stdio.h>using namespace std;int dfs(int x,int pre){    if(x==0) return 0;    for(int i=1;i<=2*pre;i++)    {        if(x-i<0) break;        if(dfs(x-i,i)==0)        return 1;    }    return 0;}int main(){    int n;    while(scanf("%d",&n)!=EOF)    {        bool flag=true;        for(int i=1;i<n;i++)        {            if(dfs(n-i,i)==0)//先手拿了i个后            {                puts("YES");                flag=false;                break;            }        }        if(flag)        puts("NO");    }}


 

A题代码:

#include<iostream>#include<cstdlib>#include<stdio.h>using namespace std;int f[41];int solve(int n){    int i;    for(i=0;i<=40;i++)    {        if(n==f[i]) return f[i];        else if(n<f[i]) break;    }    return solve(n-f[i-1]);}int main(){    f[0]=1;f[1]=2;    for(int i=2;i<=40;i++)    f[i]=f[i-2]+f[i-1];    int n;    while(scanf("%d",&n)!=EOF)    {        bool flag=true;        int i;        for(i=0;i<=40;i++)        if(n==f[i])  {puts("lose");flag=false;break;}        if(flag)        {           int d=solve(n);           cout<<d<<endl;        }    }}


 

 

原创粉丝点击