首先来看这样一道题:
Gym 101201F Illumination (Two-Sat)
题目链接
题意:一个n*n的房子,有很多灯,每个格子只能被上下方向照一次、左右方向照一次,每个灯可以选择上下或是左右照,照明长度以自身位置为中心,占用2*r+1个格子。问能否安排一种方案,使所有格子满足条件。
析:典型的Two-Sat,对于行来说,如果两个能够交叉,那么他们不能都是左右,对于列也是一样。
参考博客:这里写链接内容
算法学习博客:
学习1
各种模型
hzw缩点法
学习2
AC代码:tarjan缩点版
自己仿写的模板
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e4+7;
typedef pair<int,int> P;
struct TWOSAT
{
int n;
vector<int>G[maxn];
bool mark[maxn];
int S[maxn],c;
bool dfs(int x)
{
if(mark[x^1])return 0;
if(mark[x])return 1;
mark[x] = 1;
S[c++] = x;
for(int i=0;i<(int )G[x].size();i++)
if(!dfs(G[x][i]))return 0;
return 1;
}
void add_claues(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]] = 0;
if(!dfs(i+1))return 0;
}
}
}
return 1;
}
};
map<P,int>mp;
vector<int>row[1005],col[1005];
TWOSAT exsat;
int main()
{
int n,r,l;
cin>>n>>r>>l;
int cnt = 0;
for(int i=0;i<l;i++)
{
int x,y;
cin>>x>>y;
x--;
y--;
mp[make_pair(x,y)] = cnt++;
row[x].push_back(y);
col[y].push_back(x);
}
for(int i=0;i<n;i++)
{
sort(row[i].begin(),row[i].end());
sort(col[i].begin(),col[i].end());
}
exsat.n = cnt;
for(int i=0;i<n;i++)
{
for(int j=0;j<(int)row[i].size();j++)
{
int k = j+1;
while(k<(int)row[i].size()&&row[i][j]+r>=row[i][k])
{
exsat.add_claues(mp[P(i,row[i][j])],1,mp[P(i,row[i][k])],1);
k++;
}
}
for(int j=0;j<(int)col[i].size();j++)
{
int k = j+1;
while(k<(int)col[i].size()&&col[i][j]+r>=col[i][k])
{
exsat.add_claues(mp[P(col[i][j],i)],0,mp[P(col[i][k],i)],0);
k++;
}
}
}
if(exsat.solve())printf("YES\n");
else printf("NO\n");
return 0;
}
样例:
Sample Input
3 2 5
1 1
1 3
3 1
3 3
2 2
Sample Output
YES
Sample Input
3 2 6
1 1
1 2
1 3
3 1
3 2
3 3
Sample Output
NO
ps:事实上这道题目的数据非常水
如下的dfs也可过:(只判断灯)
#include<bits/stdc++.h>
using namespace std;
int mp[1007][1007]={0};
int ans;
int aa[1008];
int bb[1008];
int vv[1007][1007];
int n,r,l;
void dfs(int x,int y,int flag)
{
vv[x][y] = flag;
int tx,ty;
for(int i=-r;i<=r;i++)
{
if(i==0)continue;
if(!flag) tx = x,ty = i+y;
else tx = i+x,ty = y;
if(tx<1||tx>n||ty<1||ty>n)continue;
if(!mp[tx][ty])continue;
if(vv[tx][ty]==-1)
{
//vv[tx][ty] = flag^1;
dfs(tx,ty,flag^1);
if(ans==1)
{
vv[tx][ty] =-1;
return;
}
}
else if(vv[tx][ty]==flag)
{
ans = 1;
return;
}
}
}
int main()
{
memset(vv,-1,sizeof vv);
cin>>n>>r>>l;
int x,y;
for(int i=1;i<=l;i++)
{
cin>>x>>y;
mp[x][y] = 1;
aa[i] = x;
bb[i] = y;
}
int i;
for(i=1;i<=l;i++)
{
if(vv[aa[i]][bb[i]])
{
ans =0;
dfs(aa[i],bb[i],0);
if(ans==1)
{
ans =0 ;
dfs(aa[i],bb[i],1); if(ans)break;
}
}
}
if(i<=l)printf("NO\n");
else printf("YES\n");
return 0;
}