http://hi.baidu.com/joy32812/item/8d2c066065a2e92c68105b12
http://www.cnblogs.com/ambition/archive/2011/07/30/2-sat.html 这个比较推荐照这个刷,这个2-sat就基本差不多了
HDU 3062 Party 【裸题】 模版题
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=2000+123;
const int maxm=2000000+123;
struct Edge{
int v, next;
}edge[maxm];
int head[maxn], cnt;
void addedge(int u, int v)
{
edge[cnt].v=v; edge[cnt].next=head[u];
head[u]=cnt++;
}
void init()
{
memset (head, -1, sizeof(head));
cnt=0;
}
inline void add(int u, int v)
{
addedge(u, v^1);
addedge(v, u^1);
}
int id[maxn], pre[maxn], low[maxn], s[maxn], cnt0, scnt, stop;
void dfs(int u, int n)
{
int t, minc=low[u]=pre[u]=cnt0++;
s[stop++]=u;/// 存入栈中。
for (int p=head[u]; ~p; p=edge[p].next)
{
const int &v=edge[p].v;
if(-1==pre[edge[p].v])dfs(v, n);
if(low[v]<minc)minc=low[v];
}
if(minc<low[u])
{
low[u]=minc; return;
}
for (; id[t=s[--stop]]=scnt, low[t]=n, t!=u;);
scnt++;
}
void tarjan(int n)
{
memset (pre, 0xff, sizeof(pre));
cnt0=scnt=stop=0;
for (int i=0; i<n; ++i)
if(-1 == pre[i])dfs(i, n);
}
bool Two_sat(int n)
{
tarjan(n);
for (int i=0; i<n; i+=2)
{
///printf("%d %d\n", id[i], id[i|1]);
if(id[i]==id[i|1])return false;
}
return true;
}
int main()
{
int n, m;
while (~scanf("%d%d", &n, &m))
{
init();
for (int i=0; i<m; ++i)
{
int a, b, c, d; scanf("%d%d%d%d", &a, &b, &c, &d);
int u=a*2+c, v=b*2+d;
add(u, v);
///printf("u=%d sv=%d\nv=%d sv=%d\n", u, v^1, v, u^1);
// addedge(u, v^1);
// addedge(v, u^1);
}
puts(Two_sat(2*n)?"YES":"NO");
}
return 0;
}
/*
2
1
0 1 1 1
2
2
0 1 1 1
0 1 0 1
*/
POJ 3678 Katu Puzzle 接近裸题
vector <int> G[maxn];
inline void add(int u, int v)
{
///printf("u=%d v'=%d\nv=%d u'=%d\n", u, v^1, v, u^1);
G[u].push_back(v^1);
G[v].push_back(u^1);
}
int low[maxn], pre[maxn], S[maxn], Stop, scnt, cnt0, id[maxn];
void dfs(int u, int n)
{
int minc=low[u]=pre[u]=cnt0++;
S[Stop++]=u;
int sz=G[u].size();
// for_each(G[u].begin(), G[u].end(), printf);???
for (int i=0; i<sz; ++i)
{
if(-1 == pre[G[u][i]])dfs(G[u][i], n);
minc=min(minc, low[G[u][i]]);
}
if(minc<low[u])
{
low[u]=minc; return;
}
for (int t; id[t=S[--Stop]]=scnt, low[t]=n, t!=u; );
scnt++;
}
void tarjan(int n)
{
memset(pre, -1, sizeof(pre));
cnt0=scnt=Stop=0;
for (int i=0; i<n; ++i)
if(-1 == pre[i])dfs(i, n);
}
bool Two_sat(int n)
{
tarjan(2*n);
for (int i=0; i<n; ++i)
{
///printf("%d %d\n", id[i<<1], id[i<<1|1]);
if(id[i<<1]==id[i<<1|1])return false;
}
return true;
}
int main()
{
int n, m;
while (~scanf("%d%d", &n, &m))
{
for (int i=0; i<2*n; ++i)G[i].clear();
for (int i=0; i<m; ++i)
{
int a, b, c; char op[10]; scanf("%d%d%d%s", &a, &b, &c, op);
if(op[0]=='A')
{
if(c==1)
{
add(a<<1, b<<1);/// 0 0
add(a<<1, b<<1|1);/// 0 1
add(a<<1|1, b<<1);/// 1 0
}
else
add(a<<1|1, b<<1|1);/// 1 1
}
if(op[0]=='O')
{
if(c==1)
{
add(a<<1, b<<1);
}
else
{
add(a<<1|1, b<<1);
add(a<<1, b<<1|1);
add(a<<1|1, b<<1|1);
}
}
if(op[0]=='X')
{
if(c==1)
{
add(a<<1, b<<1);
add(a<<1|1, b<<1|1);
}
else
{
add(a<<1|1, b<<1);
add(a<<1, b<<1|1);
}
}
}
puts(Two_sat(n)?"YES":"NO");
}
return 0;
}
HDU 3622 Bomb Game 二分+构图, 还是很水的, 不过前提是看出是2sat.
3648Wedding spj的输出任意解, 这里要求输出的是除了解集之外的解, 就是0w之外的蓝色。 由于是spj,可以忽略格式。
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int maxn=2000+123;
const int maxm=2000000+123;
struct Edge{
int v, next;
}edge[maxm];
int head[maxn], cnt;
void addedge(int u, int v)
{
edge[cnt].v=v; edge[cnt].next=head[u];
head[u]=cnt++;
}
void init()
{
memset (head, -1, sizeof(head));
cnt=0;
}
inline void add(int u, int v)
{
addedge(u, v^1);addedge(v, u^1);
}
///************tarjan*********************///
int id[maxn], pre[maxn], low[maxn], s[maxn], cnt0, scnt, stop;
void dfs(int u, int n)
{
int t, minc=low[u]=pre[u]=cnt0++;
s[stop++]=u;
for (int p=head[u]; ~p; p=edge[p].next)
{
const int &v=edge[p].v;
if(-1==pre[edge[p].v])dfs(v, n);
if(low[v]<minc)minc=low[v];
}
if(minc<low[u])
{
low[u]=minc; return;
}
for (; id[t=s[--stop]]=scnt, low[t]=n, t!=u;);
scnt++;
}
void tarjan(int n)
{
memset (pre, 0xff, sizeof(pre));
cnt0=scnt=stop=0;
for (int i=0; i<n; ++i)
if(-1 == pre[i])dfs(i, n);
}
/// ***********scc***************///
int deg[maxn], opp[maxn];
vector<int> G[maxn];
void getback(int n)///build the artigraph in
{
memset (deg, 0, sizeof(deg));
for (int i=0; i<n; ++i)
G[i].clear();
for (int i=0; i<n; ++i)
{
opp[id[i]]=id[i^1];opp[id[i^1]]=id[i];
for (int p=head[i]; ~p; p=edge[p].next)
{
const int &v=edge[p].v;
if(id[i]!=id[v])
{
G[id[v]].push_back(id[i]);
deg[id[i]]++;
}
}
}
}
int color[maxn];
queue<int> Q;
bool toposort(int n)
{
for (int i=0; i<n; ++i)
if(deg[i]==0)Q.push(i);
while(!Q.empty())
{
int u=Q.front();
Q.pop();
if(color[u] == 0)
{
color[u]=1; color[opp[u]]=2;
}
for (int i=0; i<G[u].size(); ++i)
{
int v=G[u][i];
deg[v]--;
if(deg[v]==0)Q.push(v);
}
}
}
bool Two_sat(int n)
{
tarjan(2*n);
for (int i=0; i<n; i++)
if(id[i<<1]==id[i<<1|1])return false;
memset (opp, -1, sizeof(opp));
memset (color, 0, sizeof(color));
getback(2*n);
while (!Q.empty())Q.pop();/// 先清空队列。
toposort(scnt);/// 这里是连通分量数
return true;
}
int main()
{
int n, m;
while (scanf("%d%d", &n, &m), n&&m)
{
init();
for (int i=0; i<m; ++i)
{
int a, b; char c, d;
scanf("%d%c %d%c", &a, &c, &b, &d);
add(a*2+('h'==c), b*2+('h'==d));
}
//add(0, 1);
addedge(0, 1);
/**找出一组可行的方案坐在0w对面,
这样加边会使0h出现在可行解中,
与他同色的当然也是这个解的其他元素**/
/// 输出的是除了0w以外的其他非解元素
if(Two_sat(n))
{
for (int i=2; i<2*(n-1); ++i)
if(color[id[i]]==color[id[0]])printf("%d%c ", i>>1, i&1?'h':'w');
for (int i=2*(n-1); i<2*n; ++i)
if(color[id[i]]==color[id[0]])printf("%d%c \n", i>>1, i&1?'h':'w');
}
else printf("bad luck\n");
}
return 0;
}
hdu 1814 要求输出字典序最小的方案
http://www.cppblog.com/MatoNo1/archive/2011/07/13/150766.aspx