图片来自:http://www.hankcs.com/program/algorithm/poj-3678-katu-puzzle.html
是蓝书325的2-sat弄下来的模板代码
lrj老师的代码
这个可以用来选择字典序最小的
struct TwoSAT{ int n; vector<int> G[maxn * 2]; bool mark[maxn * 2]; int c, s[maxn * 2];///c是表示目前dfs到的个数和已经被标记的集合s bool dfs(int x){ if (mark[x ^ 1]) return false; if (mark[x]) return true; mark[x] = true; s[c++] = x; for (int i = 0; i < G[x].size(); i++) if (!dfs(G[x][i])) return false; return true; } void init(int n){ this->n = n; for (int i = 0; i < 2 * n; i++) G[i].clear(); memset(mark, 0, sizeof(mark)); } ///利用题目条件找到x和y,即假设x1[0] | x2[1] = false;即:x1[0]|!x2[1]=false ///那么我们反转该条件:即x1[1]|!x2[0] = true,即两者任意一个成立即为true ///那么我们只要交叉建图即可 void add_edge(int x, int xval, int y, int yval){ x = x * 2 + xval, y = y * 2 + yval; G[x ^ 1].push_back(y); G[y ^ 1].push_back(x); } bool solve(){ for (int i = 0; i < 2 * n; i += 2){ if (!mark[i] && !mark[i + 1]){ c = 0; if (!dfs(i)){ while (c) mark[s[--c]] = false; if (!dfs(i + 1)) return false; } } } return true; } }; TwoSAT sat;
tarjan的,利用强连通的代码
struct Tarjan{ int n; int pre[maxn*2], low[maxn*2], sccno[maxn*2], dfstime, scc_cnt; stack<int> s; vector<int> G[maxn*2]; void init(int n){ this->n = n; for (int i = 0; i <= n * 2; i++) G[i].clear(); while (!s.empty()) s.pop(); } void add_edge(int x, int y){ G[x].push_back(y); } void dfs(int u){ pre[u] = low[u] = ++dfstime; int len = G[u].size(); s.push(u); for (int i = 0; i < len; i++){ int v = G[u][i]; if (pre[v] == -1){ dfs(v); low[u] = min(low[u], low[v]); } else if (!sccno[v]){///下面为什么是pre[v]而不是low[v](两者都可以) low[u] = min(low[u], pre[v]);///因为环装最后总会变回来,一样的 } } if (low[u] == pre[u]){ scc_cnt++; while (true){ int x = s.top(); s.pop(); sccno[x] = scc_cnt; if (x == u) break; } } return ; } bool solve(){///看情况修改solve memset(pre, -1, sizeof(pre)); memset(low, 0, sizeof(low)); memset(sccno, 0, sizeof(sccno)); dfstime = scc_cnt = 0; for (int i = 0; i < 2 * n; i++){ if (pre[i] == -1) dfs(i); } for (int i = 0; i < 2 * n; i += 2){///如果两个点在同一个环里面,那么就返回false if (sccno[i] == sccno[i + 1]) return false; } return true; } }; Tarjan tar;