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

考虑步数的影响

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 1e9
using 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");  
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值