卧薪尝胆,厚积薄发。
Berzerk
Date: Thu Nov 08 10:27:16 CST 2018 In Category: NoCategory

Description:

$1\sim n$ 形成一个环,每个人有一个决策集合,可以把棋子沿顺时针移动 $k$ 格,谁先走到 $1$ 谁赢,问以每个位置作为初始点谁能赢。
$1\leqslant n\leqslant 7000$

Solution:

倒着往回推,从必胜的情况开始 $BFS$ ,同时记录一下如果这个点必败,那么能到达的必胜是确定的,如果它必胜,那根据博弈论应该所有后继节点都必胜他才必败,因此记录每个点被统计的次数,如果所有决策都统计完了就设成必败,然后加到队列里,没有被 $BFS$ 过的就是不确定。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cctype>
#include<cstring>
using namespace std;
int n;
int m[2];
#define MAXM 7010
int s[2][MAXM];
int f[2][MAXM];
int deg[2][MAXM];
bool vis[2][MAXM];
int main()
{
scanf("%d",&n);
scanf("%d",&m[0]);
for(int i = 1;i <= m[0];++i)scanf("%d",&s[0][i]);
scanf("%d",&m[1]);
for(int i = 1;i <= m[1];++i)scanf("%d",&s[1][i]);
memset(f,-1,sizeof(f));
f[0][1] = f[1][1] = 0;
queue< pair<int,int> > q;
vis[0][1] = vis[1][1] = true;
q.push(make_pair(0,1));
q.push(make_pair(1,1));
while(!q.empty())
{
pair<int,int> k = q.front();q.pop();
for(int i = 1;i <= m[k.first ^ 1];++i)
{
int p = (k.second + s[k.first ^ 1][i] - 1) % n + 1;
if(vis[k.first ^ 1][p])continue;
if(f[k.first][k.second] == 0)
{
f[k.first ^ 1][p] = 1;
vis[k.first ^ 1][p] = true;
q.push(make_pair(k.first ^ 1,p));
}
else
{
++deg[k.first ^ 1][p];
if(deg[k.first ^ 1][p] == m[k.first ^ 1])
{
f[k.first ^ 1][p] = 0;
vis[k.first ^ 1][p] = true;
q.push(make_pair(k.first ^ 1,p));
}
}
}
}
for(int i = n;i > 1;--i)
{
if(f[0][i] == 0)printf("Lose ");
if(f[0][i] == 1)printf("Win ");
if(f[0][i] == -1)printf("Loop ");
}
puts("");
for(int i = n;i > 1;--i)
{
if(f[1][i] == 0)printf("Lose ");
if(f[1][i] == 1)printf("Win ");
if(f[1][i] == -1)printf("Loop ");
}
puts("");
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡