这篇从原理上理解2-sat如何转化成图论问题简述了如何了实现算法:http://wenku.baidu.com/view/31fd7200bed5b9f3f90f1ce2.html
总的来说2-sat有两种算法,一种用dfs染色搜索出一种解,一种用tarjan(判定是否有解)+拓扑排序构造出任意一个可行解。
dfs从理论上复杂度很高,但是实际上远远达不到上界,而且可以按字典序搜索,实现也简单多了
有n个候选人,m组要求,每组要求关系到候选人中的两个人,“+i +j”代表i和j中至少有一人被选中,“-i -j”代表i和j中至少有一人不被选中。“+i -j”代表i被选中和j不被选中这两个事件至少发生一个,“-i +j”代表i不被选中和j被选中这两个事件至少发生一个。问是否存在符合所有m项要求的方案存在。
思路:每个人是两种情况,选中和不选中,根据每种关系都可以建有向边,果果的2-sat
dfs判解:
//12384K 1704MS
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 2020;
vector<int>g[N];
int n,m;
bool mark[N];
int sta[N],top;
inline void add_edge(int u,int c1,int v,int c2)
{
u=2*(u-1)+c1,v=2*(v-1)+c2;
g[u^1].push_back(v);
g[v^1].push_back(u);
}
bool dfs(int u)
{
if(mark[u^1]) return false;
if(mark[u]) return true;
mark[u]=1;
sta[++top]=u;
int sz=g[u].size();
for(int i=0;i<sz;i++)
{
int v=g[u][i];
if(dfs(v)==false) return false;
}
return true;
}
bool judge()
{
for(int i=0;i<n;i++)
{
if(!mark[i]&&!mark[i^1])
{
top=0;
if(dfs(i)==false)
{
for(int j=1;j<=top;j++)
mark[sta[j]]=0;
top=0;
if(dfs(i^1)==false) return false;
}
}
}
return true;
}
void ini()
{
for(int i=0;i<n;i++) g[i].clear();
memset(mark,0,sizeof(mark));
top=0;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
n*=2;
ini();
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
if(u>0&&v>0) add_edge(u,1,v,1);
if(u<0&&v>0) add_edge(-u,0,v,1);
if(u<0&&v<0) add_edge(-u,0,-v,0);
if(u>0&&v<0) add_edge(u,1,-v,0);
}
if(judge()) puts("1");
else puts("0");
}
return 0;
}
//12436K 1672MS C++ 1673B
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 2020;
vector<int>g[N];
int dfn[N],low[N];
int sta[N],top;
int index;
int tmp[N];
int n,m;
inline void add_edge(int u,int c1,int v,int c2)
{
u=2*(u-1)+c1,v=2*(v-1)+c2;
g[u^1].push_back(v);
g[v^1].push_back(u);
}
void tarjan(int u)
{
dfn[u]=low[u]=++index;
tmp[u]=1;
sta[++top]=u;
int sz=g[u].size();
for(int i=0;i<sz;i++)
{
int v=g[u][i];
if(tmp[v]==0) tarjan(v);
if(tmp[v]==1) low[u]=min(low[u],low[v]);
}
if(dfn[u]==low[u])
{
do
{
int v=sta[top];
tmp[v]=2;
}while(sta[top--]!=u);
}
}
void ini()
{
for(int i=0;i<n;i++) g[i].clear();
memset(tmp,0,sizeof(tmp));
index=top=0;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
n*=2;
ini();
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
if(u>0&&v>0) add_edge(u,1,v,1);
if(u<0&&v>0) add_edge(-u,0,v,1);
if(u<0&&v<0) add_edge(-u,0,-v,0);
if(u>0&&v<0) add_edge(u,1,-v,0);
}
for(int i=0;i<n;i++) if(!tmp[i]) tarjan(i);
int ans=1;
for(int i=0;i<n;i++) if(low[i]==low[i^1]) ans=0;
printf("%d\n",ans);
}
return 0;
}
POJ 3905 Perfect Election (初学2-Sat)
原文:http://blog.csdn.net/kalilili/article/details/45228607