这几天看了2-SAT有关的论文,也做了一些相关的题目,个人的一点体会。
所谓的2-SAT就是给出一对矛盾,既他们是不可能相处在一起的,比如有家庭A,B。A家庭有a0,a1两个人,B家庭有b0,b1两个人,现在要求每个家庭出席一个人组成一个集合,要是没有任何约束条件,我们可以有4种选择满足条件,即(a0,b0) (a0,b1),(a1,b0),(a1,b1)。但是我们要是给出一个约束条件 比如说a1与b1不能同时出席,即是相当于不能兼容的一队,有此,我们可供选择的就减少了,减少了虽然是(a1,b1)这种选择,但是事实上还在条件上隐性的隐藏了一种约束,就是说假如我选择了a1,在B种我是没有选择的余地了,即只能是b0。而选择了b0之后又会带出与之相关的连锁约束。可以这么说,a1和b0的命运是掌握在一起的,即任何一个被选中,另外一个也必定要选中。
我们可以在得到一组矛盾的时候,把命运连在一起的连一条变,通过求强连通分量判断是否有可行解。
另外附上这道题目的一个详解链接,想必看后对2-SAT有更好的认识
http://hi.baidu.com/fhnstephen/blog/item/7c889883900a53db9023d95d.html
顺便附上我的代码(用了吉林大的Tarjan)
#include<cmath>
#include <stdio.h>
#include <string.h>
#include <set>
#include <queue>
#include <vector>
#include <iostream>
using namespace std;
#define V 6010
int n,m;
/*==================================================*/
| Tarjan 强连通分量
| INIT: vec[]为邻接表; stop, cnt, scnt置0; pre[]置-1;
| CALL: for(i=0; i<n; ++i) if(-1==pre[i]) tarjan(i, n);
/*==================================================*/
vector<int> vec[V];
int id[V], pre[V], low[V], s[V], stop, cnt, scnt;
void tarjan(int v, int n) // vertex: 0 ~ n-1
{
int t, minc = low[v] = pre[v] = cnt++;
vector<int>::iterator pv;
s[stop++] = v;
for (pv = vec[v].begin(); pv != vec[v].end(); ++pv) {
if(-1 == pre[*pv]) tarjan(*pv, n);
if(low[*pv] < minc) minc=low[*pv];
}
if(minc < low[v]) {
low[v] = minc; return;
}
do {
id[t = s[--stop]] = scnt; low[t] = n;
} while(t != v);
++scnt; // 强连通分量的个数
}
void addedge(int s,int e)
{
// g[s].push_back(e);
// rg[e].push_back(s);
vec[s].push_back(e);
}
void Init() //初始化构图
{
int i,j,a,b,res;
memset(pre,-1,sizeof(pre));
stop=cnt=scnt=0;
char ch[5];
for(i=0;i<n;++i)
{
vec[i].clear();
//g[i].clear();
//rg[i].clear();
}
while(m --)
{
scanf("%d %d %d %s",&a,&b,&res,&ch);
a<<=1;b<<=1;
a++;b++;
if(ch[0]=='A')
{
if(res==1)
{
addedge(a-1,a);
addedge(b-1,b);
}
else
{
addedge(a,b-1);
addedge(b,a-1);
}
}
else if(ch[0]=='O')
{
if(res==1)
{
addedge(a-1,b);
addedge(b-1,a);
}
else
{
addedge(a,a-1);
addedge(b,b-1);
}
}
else
{
if(res==0)
{
addedge(a,b);
addedge(b,a);
addedge(a-1,b-1);
addedge(b-1,a-1);
}
else
{
addedge(a-1,b);
addedge(b,a-1);
addedge(a,b-1);
addedge(b-1,a);
}
}
}
}
bool Judge()
{
int i;
for(i=0; i<n; ++i)
if(-1==pre[i]) tarjan(i, n);
for(i=0;i<n;i+=2)
if(id[i]==id[i+1])
return false;
return true;
}
void Solve()
{
int i,j;
n=n+n;
Init();
if(Judge()==false)
printf("NO/n");
else
printf("YES/n");
}
int main()
{
while(scanf("%d %d",&n,&m)!=EOF)
Solve();
return 0;
}