题目地址:http://codeforces.com/gym/101201/attachments
思路:
比较明显的2-sat:每个位置只可选择行或者列,若两位置选择行发生冲突,则必有一选行另一选列,列同理。对应连边判断是否有解即可。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
#define lson l , m, rt << 1
#define rson m + 1 , r , rt << 1 | 1
using namespace std;
typedef long long ll;
const int maxn = 2000000+7;
const int maxm = 4000000+7;
int n,r,l;
struct Node
{
int x,y;
Node() {}
} p[1000+7];
struct Edge
{
int to,nxt;
} edge[maxm];
int head[maxn],tot;
void init()
{
tot=0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v)
{
edge[tot].to=v;
edge[tot].nxt=head[u];
head[u]=tot++;
}
int low[maxn],dfn[maxn],Stack[maxn],belong[maxn];
int index,top;
int scc;
bool instack[maxn];
int num[maxn];
void tarjan(int u)
{
int v;
low[u] = dfn[u] = ++index;
Stack[top++]=u;
instack[u]=true;
for(int i=head[u]; i!=-1; i=edge[i].nxt)
{
v = edge[i].to;
if(!dfn[v])
{
tarjan(v);
if(low[u]>low[v]) low[u]=low[v];
}
else if(instack[v] && low[u]>dfn[v])
{
low[u]=dfn[v];
}
}
if(low[u]==dfn[u])
{
scc++;
do
{
v=Stack[--top];
instack[v]=false;
belong[v]=scc;
num[scc]++;
}
while(v!=u);
}
}
bool solve(int n)
{
memset(dfn,0,sizeof(dfn));
memset(instack,0,sizeof(instack));
memset(num,0,sizeof(num));
index=scc=top=0;
for(int i=0; i<n; i++)
if(!dfn[i])
tarjan(i);
for(int i=0; i<n; i+=2)
if(belong[i]==belong[i^1])
return false;
return true;
}
int main()
{
scanf("%d%d%d",&n,&r,&l);
init();
for(int i=0; i<l; i++)
scanf("%d%d",&p[i].x,&p[i].y);
for(int i=0; i<l; i++)
for(int j=i+1; j<l; j++)
{
int u=(p[i].x-1)*n+p[i].y-1;
int v=(p[j].x-1)*n+p[j].y-1;
if(p[i].x==p[j].x&&abs(p[i].y-p[j].y)<=r)
{
addedge(u,v^1);
addedge(v,u^1);
}
if(p[i].y==p[j].y&&abs(p[i].x-p[j].x)<=r)
{
addedge(v^1,u);
addedge(u^1,v);
}
}
if(solve(n*n*2)) puts("YES");
else puts("NO");
return 0;
}