gym101201F Illumination 2-SAT

题目传送门

题目大意:

  给出n*n的网格,l栈灯,每盏灯可以选择照亮竖着的2*r+1的范围,或者横着的2*r+1的范围,要求一个格子不会同时被一盏以上的横着的灯照亮,也不能被一盏以上的竖着的灯照亮,所有灯必须亮着,问是否可行。

  思路:2-sat的题目,如果两盏灯之间不能同时横着放,则代表必须一横一竖,则找到了2-sat的建边关系,具体看代码。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1010;
int n,r,l,head[maxn<<1],tot;
bool vis[maxn<<1];
int s[maxn<<1],top;
struct node{
    int x,y;
}a[maxn];
struct edge{
    int to,Next;
}e[(maxn*maxn)<<1];
void init(){
    memset(head,-1,sizeof(head));
    memset(vis,0,sizeof(vis));
    tot=0;
}
void addv(int u,int v,int val){
    int tmpu=(u<<1)+val;
    int tmpv=(v<<1)+val;
    e[++tot]={tmpv,head[tmpu^1]},head[tmpu^1]=tot;//注意建边 相容的情况建边 
    e[++tot]={tmpu,head[tmpv^1]},head[tmpv^1]=tot;
}
bool dfs(int u){
    if(vis[u^1])return false;
    if(vis[u])return true;
    vis[u]=1;
    s[top++]=u;
    for(int i=head[u];i!=-1;i=e[i].Next)
    {
        if(!dfs(e[i].to))return false;
    }
    return true;
}
bool two_sat(){
    for(int i=0;i<(l<<1);i+=2){
        if(!vis[i]&&!vis[i^1]){
            top=0;
            if(!dfs(i)){
                while(top)vis[s[--top]]=0;
                if(!dfs(i^1))return false;
            }
            
        }
    }
    return true;
}
int main(){
    while(scanf("%d%d%d",&n,&r,&l)!=EOF)
    {
        init();
        for(int i=0;i<l;i++)
        {
            scanf("%d%d",&a[i].x,&a[i].y);
        }
        for(int i=0;i<l;i++)
        {
            for(int j=0;j<i;j++)
            {
                if(a[i].x==a[j].x&&abs(a[j].y-a[i].y)<2*r+1){
                    addv(i,j,0);
                };
                if(a[i].y==a[j].y&&abs(a[j].x-a[i].x)<2*r+1){
                    addv(i,j,1);
                };
            }
        }
        if(two_sat())puts("YES");
        else puts("NO");
    }
}
View Code

 

posted @ 2018-12-09 22:40  光芒万丈小太阳  阅读(208)  评论(0编辑  收藏  举报