Agc017_D Game on Tree

传送门

题目大意

给定一棵树,$1$号节点为根,两个人轮流操作,每次选择一个根节点外的点,删掉它以及它的子树,不能操作者输,求两人均采用最优策略下先手胜利还是后手胜利。

 

题解

经典问题树上删边游戏,根据论文算法合集之《组合游戏略述——浅谈SG游戏的若干拓展及变形》,每个节点的$SG$值为其所有子节点$SG$值$+1$的异或和。

判一号节点的$SG$值是否为$0$即可。

 

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define M 200020
using namespace std;
namespace IO{
	const int BS=(1<<20); int Top=0;
	char Buffer[BS],OT[BS],*OS=OT,*HD,*TL,SS[20]; const char *fin=OT+BS-1;
	char Getchar(){if(HD==TL){TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);} return (HD==TL)?EOF:*HD++;}
	void flush(){fwrite(OT,1,OS-OT,stdout);}
	void Putchar(char c){*OS++ =c;if(OS==fin)flush(),OS=OT;}
	void write(int x){
		if(!x){Putchar('0');return;} if(x<0) x=-x,Putchar('-');
		while(x) SS[++Top]=x%10,x/=10;
		while(Top) Putchar(SS[Top]+'0'),--Top;
	}
	int read(){
		int nm=0,fh=1; char cw=Getchar();
		for(;!isdigit(cw);cw=Getchar()) if(cw=='-') fh=-fh;
		for(;isdigit(cw);cw=Getchar()) nm=nm*10+(cw-'0');
		return nm*fh;
	}
}
using namespace IO;
int n,fs[M],nt[M],to[M],tmp;
void link(int x,int y){nt[tmp]=fs[x],fs[x]=tmp,to[tmp++]=y;}
int DP(int x,int last){
	int sg=0;
	for(int i=fs[x];i!=-1;i=nt[i]) if(to[i]!=last) sg^=(DP(to[i],x)+1);
	return sg;
}
int main(){
	n=read(),memset(fs,-1,sizeof(fs));
	for(int i=1;i<n;i++){int x=read(),y=read();link(x,y),link(y,x);}
	puts(DP(1,0)?"Alice":"Bob");
	return 0;
}

 

posted @ 2018-10-22 14:38  OYJason  阅读(204)  评论(0编辑  收藏  举报