自我分析:
关于 2-SAT 的代码,有一些矛盾关系一定需要搞清楚;在求解中,用到了 tarjan 算法版本的强连通(SCC)算法;在输出结果时,采用拓扑排序,并同时染色。
POJ 2723 – Get Luffy Out
POJ 3207 – Ikki’s Story IV– Panda’s Trick
POJ 3648- Wedding
POJ 3678 – Katu Puzzle
POJ 3683 – Priest John’s Busiest Day
POJ 2749 – Building roads
tarjan算法:
dfn[u] 表示 u 结点的访问时间,low[u] 表示 u 以及 u 的后代能访问到的最早的最先结点 v 的 dfn[v]
如果 dfn[u] == low[v],则说明 u 是 DFS 树中 u 所在 SCC 的起始点,这时 u 之后栈内的结点都是 u 所在 SCC 中的结点,将它们出栈并染色
计算 low[u] 的方法和无向图求割顶割边时类似
(u, v) in E
若 v 未被访问,即 (u, v) 为树枝边,low[u] = min(low[u], low[v])
若 v 已被访问,如果 v 在栈中,(u, v) 可以为后向边也可以为连接同一个 DFS 树中没有后代关系的两个结点的交叉边,
low[u] = min(low[u], dfn[v])
如果 v 不在栈中,(u, v) 为连接不同 DFS 树的交叉边,v 处于另一个 SCC,不必考虑
构图(矛盾)思路:
(1)A and B = 0 添加弧 A->!B , B->!A
(2)A and B = 1 !A->A , !B->B(3)A or B = 0 A->!A , B->!B
(4)A or B = 1 !A->B , !B->A
(5)A xor B = 0 A->B , B->A , !A->!B , !B->!A
// A == 1 && B == 0 : A -> B, !B -> !A; A == 0 && B == 1 : !A -> !B, B -> A;
(6)A xor B = 1 A->!B , B->!A , !B->A , !A->B
// 如果 x 一定在,则连一条 x + n -> x 的边(推导过程略)
const int maxn = 11000;
const int inf = 1000000000;
vector<int>edge[maxn];
int n, m;
int tmpdfn, dfn[maxn], low[maxn], inst[maxn], belong[maxn], st[maxn], top, scnt;
void tarjan( int u )
{
int i, v, t, size;
low[u] = dfn[u] = tmpdfn++;
st[top++] = u;
inst[u] = 1;
size = edge[u].size();
for( i = 0; i < size; i++ )
{
v = edge[u][i];
if( dfn[v] == -1 )
{
tarjan( v );
low[u] = min( low[u], low[v] );
}
else if( inst[v] )low[u] = min( low[u], dfn[v] );
}
if( dfn[u] == low[u] )
{
do{ belong[t = st[--top]] = scnt; inst[t] = 0; }while( t != u );
scnt++;
}
}
bool SCC()
{
int i;
top = 0;
tmpdfn = scnt = 1;
memset( dfn, -1, sizeof(dfn) );
memset( inst, 0, sizeof(inst) );
for( i = 1; i <= n * 2; i++ )if( dfn[i] == -1 )tarjan( i );
for( i = 1; i <= n; i++ )if( belong[i] == belong[i + n] )return false;
return true;
}
// 求解:建缩点后反向图,再拓扑排序(染色),同一颜色的一组即为解
int opp[maxn], in[maxn], color[maxn];
vector<int>arc[maxn];
queue<int>q;
void rebuild()
{
memset( in, 0, sizeof(in) );
int u, v, i, size;
for( i = 1; i <= n; i++ )
{
opp[belong[i]] = belong[i + n];
opp[belong[i + n]] = belong[i];
}
for( i = 1; i <= n * 2; i++ )arc[i].clear();
for( u = 1; u <= n * 2; u++ )
{
size = edge[u].size();
for( i = 0; i < size; i++ )
{
v = edge[u][i];
if( belong[u] != belong[v] )
{
arc[belong[v]].push_back( belong[u] );
in[belong[u]]++;
}
}
}
}
void topusort()
{
int i, j, u, v, size;
while( !q.empty() )q.pop();
memset( color, 0, sizeof(color) );
for( i = 1; i < scnt; i++ )if( !in[i] )
q.push( i );
while( !q.empty() )
{
u = q.front(); q.pop();
if( !color[u] )color[u] = 1, color[opp[u]] = 2;
size = arc[u].size();
for( i = 0; i < size; i++ )
{
v = arc[u][i];
in[v]--;
if( !in[v] )q.push( v );
}
}
}