P1290 欧几里德的游戏

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

 

 

 

 

题解

模拟赛的一道题,我大眼一看是博弈论的题,想都没想直接跳过(我完全不会博弈论),看了题解之后发现其实并不难;

直接看结论:

记当前状态为 $d(x,y)$ ,且 $x>y$ ,若此时 $x >= 2y$  ,则目前的操作者胜利;

下面是证明:

假定 $x=ky+r$,其中 $r = x \% y$,$k = x / y$ ,根据假设,$k>=2$,此时讨论 $d(y,r)$ 的可能情况:

$1$. 若 $d(y,r)$ 为必胜状态(即当时的操作者有必胜策略),则当前操作者( 即 $d(y,r)$ 状态下的操作者 )可以转移到 $d(y+r,r)$(取 $k-1$ 堆小的,由于 $k>=2$,肯定可以取到 )。

此时,轮到对手操作。因为必须要取正整数堆较小的,所以只能转移到 $d(y,r)$ 这个必胜状态上。那么,当前的操作者胜利。

若 $d(y,r)$ 为必败状态,其实是类似的,可以直接转移从 $d(x,y)$ 至 $d(y,r)$,把必败状态留给后手。

这样,就能把必败状态留给对手,将必胜状态留给自己,那么自己必胜!

这样的话,我们在搜索的时候如果出现 $x >= 2y$ 的情况,则当前的操作者必胜,否则转移到 $d ( x , x - y )$ ;

$Code$:

#include<cstdio>
#include<algorithm>
using namespace std;
int dfs(int x,int y,int p) //p表示当前的操作者,0是先手的人,1是后手的人 
{
    if(x==y) return p;     //当x==y,那么当前操作者必胜 
    if(x>=2*y) return p;   //结论 
    else return dfs(y,x-y,p^1);
}
int n,m,T;
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        if(n<m) swap(n,m);      //保证让第一个是较大的数 
        if(dfs(n,m,1)==0) printf("Ollie wins\n");  
        else printf("Stan wins\n");
    }
}

 

posted @ 2020-05-18 21:16  暗い之殇  阅读(171)  评论(0编辑  收藏  举报