gym101201F Illumination 2-SAT
题目大意:
给出n*n的网格,l栈灯,每盏灯可以选择照亮竖着的2*r+1的范围,或者横着的2*r+1的范围,要求一个格子不会同时被一盏以上的横着的灯照亮,也不能被一盏以上的竖着的灯照亮,所有灯必须亮着,问是否可行。
思路:2-sat的题目,如果两盏灯之间不能同时横着放,则代表必须一横一竖,则找到了2-sat的建边关系,具体看代码。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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"); } }
——愿为泰山而不骄
qq850874665~~