【博弈】移棋子游戏(BSOI3969)

【博弈】移棋子游戏

Description

给定一个有N个节点的有向无环图,图中某些节点上有棋子,两名玩家交替移动棋子。 
玩家每一步可将任意一颗棋子沿一条有向边移动到另一个点,无法移动者输掉游戏。 
对于给定的图和棋子初始位置,双方都会采取最优的行动,询问先手必胜还是先手必败。

Input

第一行,三个整数N、M、K, N表示图中节点总数,M表示图中边的条数,K表示棋子的个数 
接下来M行,每行两个整数X,Y表示有一条边从X出发指向Y。 
接下来一行,K个空格间隔的整数,表示初始时,棋子所在的节点编号

Output

若先手胜,输出"win",否则输出"lose"

Sample Input

6 8 4

2 1

2 4

1 4

1 5

4 5

1 3

3 5

3 6

1 2 4 6

Sample Output

win

Hint

N<=2000,M<=6000,1<=K<=N

Solution

一道博弈题。SG函数的模板。

值得注意的就是博弈的一些定理了,但是本蒟蒻现在都还没有弄明白,所以也就不能说出原理了。

读入数据并建图之后,我们将每一个出度为0的点的SG函数的值设置为0(别问我为什么,和某个神秘的mex函数有关)

相应的,我们可以用dfs的方式的出每一个点的SG函数值。最后整个游戏的SG函数值就是每一个棋子的SG值的异或和。(SG定理)。当SG(G)=0时,先手必败。

下面附上代码

CODE

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
struct Road{int next,to;}road[10005];
int h[2005],cnt=0;
inline void add(int x,int y){road[++cnt].to=y;road[cnt].next=h[x];h[x]=cnt;return ;}
int prep[2005];
int SG[2005];
int st[2005];
int mark[2005];
int judge[2005];
int N,M,K;
int ans;
inline void Make_SG(int v){
	if(v==0)return ;
	memset(judge,0,sizeof(judge));
	int i,j;
	for(i=h[v];i;i=road[i].next){
		j=road[i].to;
		judge[SG[j]]=1;
	}
	for(i=0;i<=N;i++){
		if(judge[i]==0){
			SG[v]=i;break;
		}
	}
	Make_SG(prep[v]);
	return ;
} 
int main(){
	cin>>N>>M>>K;
	int i,j,x,y;
	for(i=1;i<=M;i++){
		cin>>x>>y;
		add(x,y);
		prep[y]=x;mark[x]=1;
	}
	for(i=1;i<=N;i++){
		if(mark[i]==0){
			SG[i]=0;Make_SG(prep[i]);
		}
	}
	ans=0;
	for(i=1;i<=K;i++){
		cin>>x;
		ans=ans^SG[x];
	}
	if(ans)cout<<"win";
	else cout<<"lose";
	return 0;
} 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值