2-SAT几种常见关系
2-SAT这类问题一般都是对称的
两个点i,j
1. i,j不能同时选
2. i,j必须同时选
3. i,j至少选一个
4. i不存在
两种解法
第一种: 要求最小字典序-dfs
例题: HDU1814 Peaceful Commission
#include<bits/stdc++.h>
using namespace std;
const int N=8e3+5;
const int M=2e4+5;
int n,m,cnt,tot;
int head[N*2];
int sta[N*2];
bool vis[N*2];
struct node
{
int nxt,v;
}edge[M*2];
void add(int u,int v)
{
edge[cnt].v=v;
edge[cnt].nxt=head[u];
head[u]=cnt++;
}
bool dfs(int u)
{
sta[tot++]=u;
vis[u]=1;
for(int i=head[u];i!=-1;i=edge[i].nxt)
{
int v=edge[i].v;
if(vis[v^1])
return 0;
if(vis[v])
continue;
if(!dfs(v))
return 0;
}
return 1;
}
bool slove()
{
for(int i=0;i<2*n;i+=2)
{
if(!vis[i]&&!vis[i+1])
{
tot=0;
if(!dfs(i))
{
for(int i=0;i<tot;i++)
{
vis[sta[i]]=0;
}
tot=0;
if(!dfs(i+1))
return 0;
}
}
}
return 1;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
cnt=0;
memset(head,-1,sizeof head);
memset(vis,0,sizeof vis);
//memset(sta,0,sizeof sta);
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
u--,v--;
add(u,v^1);
add(v,u^1);
}
if(slove())
{
for(int i=0;i<2*n;i++)
{
if(vis[i])
printf("%d\n",i+1);
}
}
else
printf("NIE\n");
}
return 0;
}
第二种: Tarjan缩点判断是否方案存在(且输出任意一个方案)
例题:HDU3062 Party
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
struct node
{
int nxt,v;
}edge[N*2];
int n,m;
int cnt,head[2005];
void add(int u,int v)
{
edge[cnt].v=v;
edge[cnt].nxt=head[u];
head[u]=cnt++;
}
int dfn[2005],dfnIndex,low[2005],vis[2005];
int sta[2005],top;
int bcc[2005],bccIndex;
void Tarjan(int u){
dfn[u] = low[u] = ++dfnIndex;
vis[u] = true;
sta[++top] = u;
for(int i = head[u]; i!=-1; i = edge[i].nxt){
int v = edge[i].v;
if(!dfn[v]){
Tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(vis[v]){
low[u] = min(low[u], dfn[v]);
}
}
if(dfn[u] == low[u]){
++bccIndex;
do{
bcc[sta[top]] = bccIndex;
vis[sta[top]] = false;
}while(sta[top--] != u);
}
}
bool check()
{
for(int i=1;i<=n;i++)
{
if(bcc[i<<1]==bcc[(i<<1)^1])
return false;
}
return true;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
cnt=dfnIndex=bccIndex=0;
memset(vis,0,sizeof vis);
memset(dfn,0,sizeof dfn);
memset(low,0,sizeof low);
memset(sta,0,sizeof sta);
memset(head,-1,sizeof head);
for(int i=1;i<=m;i++)
{
int u,v,t1,t2;
scanf("%d%d%d%d",&u,&v,&t1,&t2);
u=(u<<1)+t1;
v=(v<<1)+t2;
add(u,v^1);
add(v,u^1);
}
for(int i=1;i<=2*n;i++)
if(!dfn[i])
Tarjan(i);
if(check())
printf("YES\n");
else
printf("NO\n");
//输出任意一个方案
//for(int i=1;i<=n;i++)
//{
// if(bcc[i<<1]<bcc[(i<<1)|1])
// printf("%d ",i);
//}
}
return 0;
}