[ZOJ3316]Game
题意:有一个棋盘,棋盘上有一些棋子,两个人轮流拿棋,第一个人可以随意拿,以后每一个人拿走的棋子与上一个人拿走的棋子的曼哈顿距离不得超过$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的更多相关文章
- 【ZOJ3316】Game(带花树)
[ZOJ3316]Game(带花树) 题面 Vjudge 翻译: 给定棋盘上\(n\)个旗子 一开始先手可以随便拿, 然后每次都不能取离上次的曼哈顿距离超过\(L\)的旗子 谁不能动谁输. 问后手能否 ...
- [ZOJ3316]:Game
题面 vjudge Sol 有一个棋盘,棋盘上有一些棋子,两个人轮流拿棋,第一个人可以随意拿,以后每一个人拿走的棋子与上一个人拿走的棋子的曼哈顿距离不得超过L,无法拿棋的人输,问后手能否胜利 首先距离 ...
随机推荐
- 上海GDG活动有感
本周参加了场上海的GDG活动.本次活动的主办方 先介绍一下: GDG Shanghai 上海GDG(Google开发者社区,以前是GTUG, Google技术用户组) ,众所周知,Google的搜索引 ...
- oracle11g 使用数据泵导出导入数据
终于搞定了 快写个笔记 记录下. 删除用户的时候提示已经登录了不能删除,这个需要把登录的session结束掉. select username,sid,serial# from v$session w ...
- linux编译动态库 fPIC作用
在生成动态库时,常常习惯性的加上fPIC选项,fPIC有什么作用和意义,加不加有什么区别,这里做下小结: fPIC的全称是 Position Independent Code, 用于生成位置无关代码. ...
- 51nodeE 斜率最大
题目传送门 这道题只要证明最佳解一定在相邻两个点之间的好啦 这个自己证一证就okay啦 而且我发现n方的算法可以过耶... #include<cstdio> #include<cst ...
- 阶段性总结⓵触摸事件&手势识别⓶Quartz2D绘图⓷CALayer图层⓸CAAnimation⓹UIDynamic UI动力学⓺KVC&KVO
知识点复习 1. 触摸事件&手势识别 1> 4个触摸事件,针对视图的 2> 6个手势识别(除了用代码添加,也可以用Storyboard添加) 附加在某一个特定视图上的, ...
- 对象是否拥有某个属性,in和for in以及object.hasOwnProperty('×××')的异同,以及Object.defineProperty(),Object.keys(),Object.getOwnPropertyNames()的用法
1.在某个对象是否拥有某个属性,判断的方法有很多,常用的方法就是object.hasOwnProperty('×××'),这个方法是不包括对象原型链上的方法的,举个例子: var obj = { na ...
- mongoDB的文档查询
1.简单查询: find() 方法以非结构化的方式来显示所有文档. 语法 MongoDB 查询数据的语法格式如下: collection是集合名字,注意应该是当前数据库的集合,collect ...
- (转载)常用的Python库
http://forum.ubuntu.com.cn/viewtopic.php?f=63&t=249573&p=2640959 Tkinter ---- Python默认的图形界面接 ...
- UVA 10385 Duathlon
Problem HDuathlonInput: standard inputOutput: standard outputTime Limit: 15 seconds A duathlon is a ...
- IC卡的传输协议(2)-块传输协议T=1续【转】
转自:http://bbs.ednchina.com/BLOG_ARTICLE_172025.HTM (3)容错操作 先来看一下容错的规则定义. * 复位应答后,第一个数据块是由终端发往IC卡的,而且 ...