【loli的胡策】测试3.28 T1(博弈)

题目:

这里写图片描述
这里写图片描述

题解:

一看到是博弈就吓住了,害怕是什么SG乱搞。然而这道题目并不要什么SG函数
我们发现所有的状态只有2n个点,即Alice/Bob先手,棋子在第i个位置。那么显然棋子在1的两个状态都是必败态
然后是个博弈常用的结论:
如果一个状态可以转移到任何一个必败态,则这个状态是必胜态
如果一个状态只能转移到必胜态,则这个状态是必败态
那么我们可以根据这个从1开始暴力标记,当一个节点是必败态的时候,我们把ta所有的前驱标为必胜态
当一个节点是必胜态的时候,我们把ta所有的前驱出度–,当减到0的时候就是必败态啦

代码:

#include <queue>
#include <cstdio>
using namespace std;
const int N=7005;
int a[N],b[N],end[N*2],du[N*2];bool vis[N*2];
int main()
{
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    int n;scanf("%d",&n);
    scanf("%d",&a[0]);
    for (int i=1;i<=a[0];i++) scanf("%d",&a[i]);
    scanf("%d",&b[0]);
    for (int i=1;i<=b[0];i++) scanf("%d",&b[i]);
    end[0]=end[n]=-1;vis[0]=vis[n]=1;
    queue<int>q;q.push(0);q.push(n);
    while (!q.empty())
    {
        int now=q.front(); q.pop();
        if (now>=n)//b
        {
            for (int i=1;i<=a[0];i++)
            {
                int pre=(now-a[i])%n;
                if (vis[pre]) continue;
                if (end[now]==-1) vis[pre]=1,end[pre]=1,q.push(pre);
                else if (++du[pre]==a[0]) vis[pre]=1,end[pre]=-1,q.push(pre); 
            }
        }
        else
        {
            for (int i=1;i<=b[0];i++)
            {
                int pre=(now-b[i]+n)%n+n;
                if (vis[pre]) continue;
                if (end[now]==-1) vis[pre]=1,end[pre]=1,q.push(pre);
                else if (++du[pre]==b[0]) vis[pre]=1,end[pre]=-1,q.push(pre); 
            }
        }
    }

    for (int i=1;i<n;i++)
      if (end[i]==1) printf("Win ");
      else if (end[i]==-1) printf("Lose ");
      else printf("Loop ");
    printf("\n");
    for (int i=1;i<n;i++)
      if (end[i+n]==1) printf("Win ");
      else if (end[i+n]==-1) printf("Lose ");
      else printf("Loop ");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值