Gym 101201.F

来源:互联网 发布:小学安全网络知识竞赛 编辑:程序博客网 时间:2024/04/27 19:51

题意:给你一个n*n的方格,里面有k个方格有灯,每个灯可以选择左右发射长度r格的光或者上下发射,问你是否有一种方案,使得每个格子,不会被同为纵向(横向)的多束光照射。nk1000

思路:2-SAT模板题。枚举每一对灯,如果两者光线有矛盾,加逻辑语句即可。

#include <bits/stdc++.h>using namespace std;const int maxn = 2000 + 5;struct TwoSat{//2i为假  2i+1为真    int n;    vector<int>G[maxn * 2];    bool mark[maxn * 2];    int S[maxn * 2], c;    void init(int n)    {        this->n = n;        for(int i = 0; i < n * 2; i++)   G[i].clear(), mark[i] = 0;    }    bool dfs(int x)    {        if(mark[x^1])   return false;        if(mark[x]) return true;        mark[x] = true;        S[c++] = x;        for(auto o : G[x])  if(!dfs(o)) return false;        return true;    }    void add_clause(int x, int xval, int y, int yval)    {        x = x * 2 + xval;        y = y * 2 + yval;        G[x^1].push_back(y);        G[y^1].push_back(x);    }    bool solve()    {        for(int i = 0; i < n * 2; 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;    }}solver;struct node{int x, y;}nodes[maxn];int main(){    int n, r, l;    scanf("%d%d%d", &n, &r, &l);    for(int i = 0, x, y; i < l; i++)    {        scanf("%d%d", &x, &y);        nodes[i] = {x, y};    }    solver.init(l);    for(int i = 0; i < l; i++)    {        for(int j = i + 1; j < l; j++)        {            if(nodes[i].x == nodes[j].x && abs(nodes[i].y - nodes[j].y) <= r)            {                solver.add_clause(i, 0, j, 0);            }            if(nodes[i].y == nodes[j].y && abs(nodes[i].x - nodes[j].x) <= r)            {                solver.add_clause(i, 1, j, 1);            }        }    }    if(solver.solve())  puts("YES");    else puts("NO");    return 0;}
原创粉丝点击