博弈问题总集第五类----Every-SG

来源:互联网 发布:视频剪辑for mac 编辑:程序博客网 时间:2024/05/16 15:55

考虑步数的影响

Every-SG游戏是指由很多单一游戏组成,每次每个玩家需要在每一个能够操作的单一游戏上进行操作,最后结束的那个单一游戏的胜负决定整个游戏的胜负。那么对于每个玩家来说,都希望自己必胜的游戏玩得尽量长,自己必败的游戏玩的尽量短。这和普通SG游戏不同的一点就是步数也会对最终结果产生影响

那么就在求解SG函数的过程中引入记录最优步数的step,如果当前状态是必胜态,那么当前状态的step就是所有是必败态的后继的step的最大值;如果当前状态是必败态,step就是所有后继状态step的最小值。这个也比较好理解,因为每个人都会采取对自己最有利的策略。最后如果步数最大的那个单一游戏会在奇数步结束那么先手就是必胜的

题目:

[HDU3595] GG and MM

题意:

两个人玩游戏,每次只能在石子数多的那一堆取出石子数少的那一堆的k倍的石子,同时有n个这样的游戏同时进行,谁不能取谁输。

题解:

对于自己必胜的游戏,要让游戏尽可能晚的结束,对于自己必输的游戏,要让游戏尽早的结束,这样才能让自己必胜的游戏覆盖掉自己必输的游戏,让最后结束的游戏是自己必胜的游戏,这样对于整个游戏自己就是必胜的。

其实我并不太明白网上题解说的【控制步数】,但我打的是纯粹的【暴力】,如果当前状态是必胜态,那么当前状态的step就是所有是必败态的后继的step的最大值;如果当前状态是必败态,step就是所有后继状态step的最小值。

代码:

#include <cstdio>#include <cstring>#include <iostream>#define INF 1e9using namespace std;int sg[1005][1005],step[1005][1005];int get_sg(int x,int y){    if (sg[x][y]!=-1) return sg[x][y];    if (x>y) swap(x,y);    if (x==0) {step[x][y]=step[y][x]=sg[x][y]=sg[y][x]=0;return 0;}    int maxx=0,minn=INF;    for (int i=x;i<=y;i+=x)    {        if (!get_sg(x,y-i))        {            maxx=max(maxx,step[x][y-i]);            sg[x][y]=sg[y][x]=1;        }        else minn=min(minn,step[x][y-i]);    }     if (sg[x][y]==1) {step[x][y]=step[y][x]=maxx+1;return 1;}    step[x][y]=step[y][x]=minn+1;    sg[x][y]=sg[y][x]=0;    return 0;}int main(){    int n,p,q;    memset(sg,-1,sizeof(sg));    while (~scanf("%d",&n))    {        int gg=0,mm=0;        for (int i=1;i<=n;i++)        {            scanf("%d%d",&p,&q);            if (get_sg(p,q)) mm=max(mm,step[p][q]);            else gg=max(gg,step[p][q]);        }        if (mm>gg) printf("MM\n");else printf("GG\n");      }}