题意:有一个棋盘,棋盘上有一些棋子,两个人轮流拿棋,第一个人可以随意拿,以后每一个人拿走的棋子与上一个人拿走的棋子的曼哈顿距离不得超过$L$,无法拿棋的人输,问后手能否胜利

把棋子看做点,如果两个棋子的距离$\leq L$就连一条边,显然一局游戏只能在一个连通块里玩

如果某一个连通块只有一个点,那么先手拿走它,后手就输了

如果一个连通块有很多个点,做一次匹配,如果有完美匹配,那么后手胜利,否则先手胜利

为什么?

假设$A$先手,$B$后手,如果没有完美匹配,那么$A$可以选择一个非匹配点开始游戏,每次$B$都必须选择一个匹配点,然后$A$可以选择走匹配边,如此往复,最后一定是$A$走到某个地方使得$B$不能再走了(如果$B$还能走并且使得$A$不能走,说明这个图里还有增广路,不是最大匹配)

如果有完美匹配,$A$一开始只能选择匹配点,每次$B$可以走匹配边,如此往复,最后一定是$A$走不动了(如果$A$还能走并使得$B$走不动,那么最后到的是一个未匹配点,图就不是完美匹配了)

所以建出图之后直接跑带花树,判断是否存在完美匹配即可

#include<stdio.h>
#include<string.h>
int n,head,tail,h[400],nex[160000],to[160000],q[400],fa[400],type[400],match[400],pre[400],tm[400],M;
void swap(int&a,int&b){a^=b^=a^=b;}
void add(int a,int b){
	M++;
	to[M]=b;
	nex[M]=h[a];
	h[a]=M;
}
int get(int x){return(fa[x]==x)?x:(fa[x]=get(fa[x]));}
int lca(int x,int y){
	M++;
	while(1){
		if(x){
			x=get(x);
			if(tm[x]==M)return x;
			tm[x]=M;
			x=pre[match[x]];
		}
		swap(x,y);
	}
}
void blossom(int x,int y,int p){
	while(get(x)!=p){
		pre[x]=y;
		y=match[x];
		if(type[y]==2){
			type[y]=1;
			tail++;
			q[tail]=y;
		}
		if(fa[x]==x)fa[x]=p;
		if(fa[y]==y)fa[y]=p;
		x=pre[y];
	}
}
void bfs(int x){
	int i,now,las;
	memset(pre,0,sizeof(pre));
	memset(type,0,sizeof(type));
	for(i=1;i<=n;i++)fa[i]=i;
	type[x]=1;
	head=tail=1;
	q[1]=x;
	while(head<=tail){
		x=q[head];
		head++;
		for(i=h[x];i;i=nex[i]){
			if(type[to[i]]==2||get(x)==get(to[i]))continue;
			if(type[to[i]]==0){
				pre[to[i]]=x;
				type[to[i]]=2;
				if(match[to[i]]==0){
					now=to[i];
					while(now){
						las=match[pre[now]];
						match[now]=pre[now];
						match[pre[now]]=now;
						now=las;
					}
					return;
				}
				type[match[to[i]]]=1;
				tail++;
				q[tail]=match[to[i]];
			}else{
				now=lca(x,to[i]);
				blossom(x,to[i],now);
				blossom(to[i],x,now);
			}
		}
	}
}
int x[400],y[400];
int abs(int x){return x>0?x:-x;}
int dis(int i,int j){
	return abs(x[i]-x[j])+abs(y[i]-y[j]);
}
int main(){
	int i,j,L;
	while(~scanf("%d",&n)){
		memset(h,0,sizeof(h));
		memset(match,0,sizeof(match));
		memset(tm,0,sizeof(tm));
		M=0;
		for(i=1;i<=n;i++)scanf("%d%d",x+i,y+i);
		scanf("%d",&L);
		for(i=1;i<=n;i++){
			for(j=1;j<=n;j++){
				if(i!=j&&dis(i,j)<=L)add(i,j);
			}
		}
		M=0;
		for(i=1;i<=n;i++){
			if(match[i]==0)bfs(i);
		}
		M=1;
		for(i=1;i<=n;i++){
			if(match[i]==0){
				puts("NO");
				M=0;
				break;
			}
		}
		if(M)puts("YES");
	}
}

[ZOJ3316]Game的更多相关文章

  1. 【ZOJ3316】Game(带花树)

    [ZOJ3316]Game(带花树) 题面 Vjudge 翻译: 给定棋盘上\(n\)个旗子 一开始先手可以随便拿, 然后每次都不能取离上次的曼哈顿距离超过\(L\)的旗子 谁不能动谁输. 问后手能否 ...

  2. [ZOJ3316]:Game

    题面 vjudge Sol 有一个棋盘,棋盘上有一些棋子,两个人轮流拿棋,第一个人可以随意拿,以后每一个人拿走的棋子与上一个人拿走的棋子的曼哈顿距离不得超过L,无法拿棋的人输,问后手能否胜利 首先距离 ...

随机推荐

  1. 一个 React & Redux的目录树

    |-----------------------------------------| | | | React & Redux | | | |------------------------- ...

  2. springMvc--请求的跳转和传值

    springMvc--请求的跳转和传值 目录 forword跳转页面的三种方式 1.使用serlvet 2.使用Model对象 3.使用ModelAndView redirect跳转到页面 使用ser ...

  3. poj3683 2-sat Priest John's Busiest Day

    Description John is the only priest in his town. September 1st is the John's busiest day in a year b ...

  4. Windows下安装Mycat

    Mycat 首先在安装Mycat之前,需要安装JDK1.7以上,可以在cmd环境下输入 java -version 查看本地安装的java版本 如果未安装或者版本在1.7以下,请重新安装. 安装JDK ...

  5. Spring学习--引用其他Bean , 内部Bean

    引用其他Bean: 组成应用程序的 Bean 经常需要相互协作以完成应用程序的功能 , 要使 Bean 能够相互访问, 就必须在 Bean 配置文件中指定对 Bean 的引用. 在 Bean 的配置文 ...

  6. struts2学习笔记(三)

    一. Struts2 的验证 1). 验证分为两种: > 声明式验证* >> 对哪个 Action 或 Model 的那个字段进行验证 >> 使用什么验证规则 >& ...

  7. vivo面试学习1(io和nio)

    一.io流(一次从open到底层的操作) 输入和输出流 IO流 字节流 Reader.Writer 字符流 InputStream.OutputStream 字节流:可以处理所有bit为单位存储的文件 ...

  8. Java序列化与反序列化是什么?为什么需要序列化与反序列化?如何实现Java序列化与反序列化?

    Java序列化与反序列化是什么?为什么需要序列化与反序列化?如何实现Java序列化与反序列化?本文围绕这些问题进行了探讨.  1.Java序列化与反序列化  Java序列化是指把Java对象转换为字节 ...

  9. javascript中实例方法与类方法的区别

    在javascript中,类有静态属性和实例属性之分,也有静态方法和实例方法之分 类属性(静态属性):通过类直接访问,不需要声明类的实例来访问 类方法(静态方法):通过类直接访问,不需要声明类的实例来 ...

  10. python 学习笔记 aiohttp

    asyncio可以实现单进程并发IO操作,如果仅用在客户端,发挥的威力并不大,如果把asyncio用在服务器端,由于http链接就是IO操作, 因此可以用单线程+coroutine实现多客户的高并发支 ...