Gym 101201F Illumination(2-sat)

来源:互联网 发布:启明英语听说软件 编辑:程序博客网 时间:2024/06/01 09:35

题意:给定一个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;}