链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3726
算法见:http://fanhq666.blog.163.com/blog/static/8194342620120304463580/
题意:棋盘上有n个点,现在两个人轮流在移除一个子,每次移除的子距离上次移除的子曼哈顿距离小于L。最后不能移除的人输。
分析:将距离小于L的点连边。如果一个连通块不是是完备匹配,先手一定可以让自己走到一个没有匹配的点上,然后后手就不能移除子了,如果后手可以移除子,那么就有了新的匹配,现在就是一个完备匹配了。
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 400
#define Mm 200005
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
struct edge {
int v,next;
}e[Mm];
struct point {
int x,y;
}p[Mn];
int dis(point a,point b) {
return abs(a.x-b.x)+abs(a.y-b.y);
}
int tot,head[Mn];
void addedge(int u,int v) {
e[tot].v=v;
e[tot].next=head[u];
head[u]=tot++;
}
int pre[Mn];
int findpre(int x) {
return x==pre[x]?pre[x]:pre[x]=findpre(pre[pre[x]]);
}
void ol(int a,int b) {
a=findpre(a);
b=findpre(b);
if(a!=b) pre[a]=b;
}
int n,lk[Mn],vis[Mn],mark[Mn],match[Mn],ne[Mn];
int lca(int x,int y) {
static int t=0;t++;
while(1) {
if(x!=-1) {
x=findpre(x);
if(vis[x]==t) return x;
vis[x]=t;
if(match[x]!=-1) x=ne[match[x]];
else x=-1;
}
swap(x,y);
}
}
queue<int> q;
void group(int a,int p) {
while(a!=p) {
int b=match[a],c=ne[b];
if(findpre(c)!=p) ne[c]=b;
if(mark[b]==2) mark[b]=1,q.push(b);
if(mark[c]==2) mark[c]=1,q.push(c);
ol(a,b),ol(b,c);
a=c;
}
}
void aug(int s) {
for(int i=0;i<=n;i++) {
ne[i]=-1;
pre[i]=i;
mark[i]=0;
vis[i]=-1;
}
mark[s]=1;
while(!q.empty()) q.pop();
q.push(s);
while((!q.empty())&&match[s]==-1) {
int u=q.front();
q.pop();
for(int i=head[u];~i;i=e[i].next) {
int v=e[i].v;
if(match[u]==v||findpre(u)==findpre(v)||mark[v]==2) continue;
if(mark[v]==1) {
int r=lca(u,v);
if(findpre(u)!=r) ne[u]=v;
if(findpre(v)!=r) ne[v]=u;
group(u,r);
group(v,r);
} else if(match[v]==-1) {
ne[v]=u;
for(int x=v;~x;) {
int y=ne[x];
int mv=match[y];
match[x]=y,match[y]=x;
x=mv;
}
break;
} else {
ne[v]=u;
q.push(match[v]);
mark[match[v]]=1;
mark[v]=2;
}
}
}
}
void init() {
tot=0;
CLR(head,-1);
}
int main() {
while(~scanf("%d",&n)) {
int l;init();
for(int i=1;i<=n;i++)
scanf("%d%d",&p[i].x,&p[i].y);
scanf("%d",&l);
for(int i=1;i<n;i++) {
for(int j=i+1;j<=n;j++) {
if(dis(p[i],p[j])<=l) {
addedge(i,j);
addedge(j,i);
}
}
}
for(int i=1;i<=n;i++) match[i]=-1;
for(int i=1;i<=n;i++) {
if(match[i]==-1) aug(i);
}
int ans=0;
for(int i=1;i<=n;i++) {
if(match[i]!=-1) ans++;
}
if(ans==n) {
printf("YES\n");
} else printf("NO\n");
}
return 0;
}