码迷,mamicode.com
首页 > 其他好文 > 详细

[ZOJ3316]Game

时间:2018-03-16 11:20:29      阅读:170      评论:0      收藏:0      [点我收藏+]

标签:tin   i++   set   while   gpo   oss   match   turn   wap   

题意:有一个棋盘,棋盘上有一些棋子,两个人轮流拿棋,第一个人可以随意拿,以后每一个人拿走的棋子与上一个人拿走的棋子的曼哈顿距离不得超过$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

标签:tin   i++   set   while   gpo   oss   match   turn   wap   

原文地址:https://www.cnblogs.com/jefflyy/p/8579376.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!