题目链接:A Chess Game
首先需要了解SG函数及SG定理:博弈论 SG函数,
Nim游戏与SG函数 ——博弈论小结
在了解了以上之后就好做了。首先对于一个有向图来说,每个点都有一个sg函数值,如果该值为0,则此位置为先手必败即P位置,否则为先手必胜即N位置。而所有的棋子的位置的sg值异或之和为0即输,否则则赢。现在的目标就是求每个点的sg值,按照sg函数的定义,求出每个点的sg值。注意:求sg值是自底向上的,我这里用了两种方法,一种为dfs,一种为拓扑排序。
代码如下:
方法一:
/*************************************************************************
> File Name: main.cpp
> Author:Eagles
> Mail:None
> Created Time: 2018年11月06日 星期二 11时23分33秒
> Description:POJ2425
************************************************************************/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
#define N 1005
struct edge
{
int to;
int nex;
}E[N*N];
int head[N];
int sg[N];
bool vis[N];
int n,cnt;
void addEdge(int a, int b)加边
{
E[cnt].to=b;
E[cnt].nex=head[a];
head[a]=cnt++;
}
void init()//初始化
{
memset(head,-1,sizeof(head));
memset(sg,0,sizeof(sg));
memset(vis,false,sizeof(vis));
cnt=0;
for (int i=0; i<n; i++)
{
int num;
scanf("%d",&num);
while (num--)
{
int to;
scanf("%d",&to);
addEdge(i,to);
}
}
}
void dfs(int dot)
{
vis[dot]=true;
if (head[dot] == -1)
{
sg[dot]=0;
return ;
}
int hash_val[N];
memset(hash_val,0,sizeof(hash_val));
for (int i=head[dot]; i!=-1; i=E[i].nex)
{
if (!vis[E[i].to])
{
dfs(E[i].to);
}
hash_val[sg[E[i].to]]=1;
}
for (int i=0; i<n; i++)
{
if (hash_val[i] == 0)
{
sg[dot]=i;
break;
}
}
}
void solve()
{
for (int i=0; i<n; i++)
{
if (!vis[i])
dfs(i);
}
int num;
while (~scanf("%d",&num)&&num)
{
int ans=0;
while (num--)
{
int to;
scanf("%d",&to);
ans^=sg[to];
}
printf("%s\n",ans==0?"LOSE":"WIN");
}
}
void print()
{
for (int i=0; i<n; i++)
if (!vis[i])
dfs(i);
for (int i=0; i<n; i++)
printf("%d ",sg[i]);
printf("\n");
}
int main()
{
while (~scanf("%d",&n))
{
init();
solve();
}
return 0;
}
方法二:
/*************************************************************************
> File Name: main.cpp
> Author:Eagles
> Mail:None
> Created Time: 2018年11月06日 星期二 19时48分51秒
> Description:poj2425
************************************************************************/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
#define N 1005
struct edge
{
int to;
int nex;
int val;
}E[N*N];
int head[N];
int sg[N];
int hash_val[N];
int indeg[N];//入度
queue<int>q;//用来存拓扑排序后的序列
int n,cnt;
void addEdge(int a, int b, int val)
{
E[cnt].to=b;
E[cnt].val=val;
E[cnt].nex=head[a];
head[a]=cnt++;
}
void init()
{
memset(head,-1,sizeof(head));
cnt=0;
memset(sg,0,sizeof(head));
memset(hash_val,0,sizeof(hash_val));
memset(indeg,0,sizeof(indeg));
while (!q.empty())
q.pop();
for (int i=0; i<n; i++)
{
int num;
scanf("%d",&num);
while (num--)
{
int a;
scanf("%d",&a);
addEdge(i,a,1);//本来的边
addEdge(a,i,-1);//加了一条反向的“虚边”,为了拓扑排序
indeg[i]++;//拓扑排序反向
}
}
}
void top_sort()//拓扑排序
{
queue<int>tmp_q;
for (int i=0; i<n; i++)
if (indeg[i]==0)
tmp_q.push(i);
while (!tmp_q.empty())
{
int cur=tmp_q.front();
tmp_q.pop();
q.push(cur);
for (int i=head[cur]; i!=-1; i=E[i].nex)
{
if (E[i].val == -1)
{
indeg[E[i].to]--;
if (indeg[E[i].to] == 0)
tmp_q.push(E[i].to);
}
}
}
}
void sg_val()
{
while (!q.empty())//自底向上计算sg值,最前面的肯定是出度为0的点
{
int cur=q.front();
q.pop();
memset(hash_val,0,sizeof(hash_val));
for (int i=head[cur]; i!=-1; i=E[i].nex)
{
if (E[i].val == 1)
{
hash_val[sg[E[i].to]]=1;
}
}
for (int i=0; i<n; i++)
{
if (hash_val[i] == 0)
{
sg[cur]=i;
break;
}
}
}
}
void solve()
{
top_sort();
sg_val();
int num;
while (~scanf("%d",&num)&&num)
{
int ans=0;
while (num--)
{
int a;
scanf("%d",&a);
ans^=sg[a];
}
printf("%s\n",ans==0?"LOSE":"WIN");
}
}
void print()
{
top_sort();
sg_val();
for (int i=0; i<n; i++)
printf("%d ",sg[i]);
printf("\n");
}
int main()
{
while (~scanf("%d",&n))
{
init();
solve();
}
return 0;
}