题意:给定一个n*n的格子,其中有l盏灯,每盏灯能照亮(2 *r+1)的一行或一列,每个格子只能被一行的一盏灯和一列的一盏灯照亮,否则就不满足条件,问是否存在一种方案,打开所有的灯并且满足条件?
思路:每个格子有两种状态,用A1表示被行中的灯照亮,A2表示被列中的灯照亮。
那么对于同一行的可以互相照射两盏灯A,B,则有A1->B2, B1->A1.
对于同一列的可以互相照射两盏灯A,B,则有A2->B1, B2->A1.
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e3 + 10;
int x[maxn], y[maxn];
bool mark[maxn * 2];
int S[maxn * 2], c;
vector<int> G[maxn * 2];
int n, r, l;
void add(int x, int y){
G[x].push_back(y);
}
void init(int n){
for(int i = 0; i < 2 * l; ++i) G[i].clear();
memset(mark, 0, sizeof mark);
}
bool dfs(int x){
if(mark[x^1]) return false;
if(mark[x]) return true;
mark[x] = true;
S[c++] = x;
for(int i = 0; i < G[x].size(); ++i){
if(!dfs(G[x][i])) return false;
}
return true;
}
bool solve(){
for(int i = 0; i < 2 * l; i += 2){
if(!mark[i] && !mark[i + 1]){
c = 0;
if(!dfs(i)){
while(c > 0) mark[S[--c]] = false;
if(!dfs(i + 1)) return false;
}
}
}
return true;
}
int main(){
while(scanf("%d%d%d", &n, &r, &l) == 3){
init(l);
for(int i = 0; i < l; ++i){
scanf("%d%d", &x[i], &y[i]);
}
for(int i = 0; i < l; ++i){
for(int j = i + 1; j < l; ++j){
if(x[i] == x[j]){
if(abs(y[i] - y[j]) <= 2 * r) {
add(2 * i, (2 * j)^1);
add(2 * j, (2 * i)^1);
}
}
else if(y[i] == y[j]){
if(abs(x[i] - x[j]) <= 2 * r){
add((2 * i)^1, 2 * j);
add((2 * j)^1, 2 * i);
}
}
}
}
printf("%s\n", solve() ? "YES" : "NO");
}
return 0;
}