终于搞懂了\(2-sat\)。实际上是个挺简单的东西,像网络流一样关键在于建模。

问题:\(n\)个数\(A\),可以选择\(0\)和\(1\),现在给你\(m\)组条件\(A\),\(B\),对每个条件要求\(A\)为真或者\(B\)为真。

\(2-sat\)的建图方法:把每一个或条件拆成两个。例如对于条件\(A\) \(or\) \(B\):

  • 如果\(A\)为假,那么\(B\)必须为真。(\(A_false\) \(->\) \(B_true\))
  • 如果\(B\)为假,那么\(A\)必须为真。(\(B_false\) \(->\) \(A_true\))

即一条边代表一条指向条件,选择一个点就代表着同时要选择它的闭合子图中的其他点。容易知道:如果存在一个圈,其中同时包含\(x_false\)和\(x_true\),那么取值选择无解。这个过程可以用\(Tarjan\)求\(scc\)来做。

可行解的构造:把原图缩成若干\(scc\)后,对每个条件\(A\),我们优先选对应点拓扑序比较大的那个值,这样就可以向着最容易出解的方向选择。(选择一个点就代表着同时要选择它的闭合子图中的其他点。)

特定解的构造:暴力。此问题\(np\)完全。

#include <bits/stdc++.h>
using namespace std; const int N = 200 + 5;
const int M = 2000 + 5; struct Graph {
int cnt, head[N]; struct Edge {
int nxt, to;
}e[M]; void clear () {
cnt = -1;
memset (head, -1, sizeof (head));
} void add_edge (int u, int v) {
e[++cnt] = (Edge) {head[u], v}; head[u] = cnt;
} stack <int> sta; int _dfn, _sccid; int inq[N], dfn[N], low[N], sccid[N]; void Tarjan (int u) {
dfn[u] = low[u] = ++_dfn;
inq[u] = true; sta.push (u);
for (int i = head[u]; ~i; i = e[i].nxt) {
int v = e[i].to;
if (!dfn[v]) {
Tarjan (v);
low[u] = min (low[u], low[v]);
} else if (inq[v]) {
low[u] = min (low[u], dfn[v]);
}
}
if (dfn[u] == low[u]) {
int tmp; ++_sccid;
do {
tmp = sta.top ();
inq[tmp] = false;
sccid[tmp] = _sccid;
sta.pop ();
}while (tmp != u);
}
} void get_scc (int n) {
_dfn = _sccid = 0;
memset (inq, 0, sizeof (inq));
memset (dfn, 0, sizeof (dfn));
for (int i = 1; i <= n; ++i) {
if (!dfn[i]) Tarjan (i);
}
} }G; int T, n, m; int node (int x, int t) {
return n * t + x;
} int main () {
// freopen ("data.in", "r", stdin);
cin >> T;
while (T--) {
cin >> n >> m; G.clear ();
for (int i = 1; i <= m; ++i) {
static int u, v, t1, t2;
while (!isalpha (t1 = getchar ())); cin >> u;
while (!isalpha (t2 = getchar ())); cin >> v;
t1 = t1 == 'm' ? 0 : 1;
t2 = t2 == 'm' ? 0 : 1;
G.add_edge (node (u, !t1), node (v, t2));
G.add_edge (node (v, !t2), node (u, t1));
}
G.get_scc (n << 1);
bool succ = true;
for (int i = 1; i <= n; ++i) {
if (G.sccid[node (i, 0)] == G.sccid[node (i, 1)]) {
succ = false; break;
}
}
puts (succ ? "GOOD" : "BAD");
}
}

最新文章

  1. 微信小程序-关于重定向问题
  2. 无线安全审计工具 Fern WiFi Cracker
  3. PHP 数组的遍历的几种方式(以及foreach与for/while+each效率的比较)
  4. 2014 Hangjs 见闻流水账第二天
  5. select2取值报错,Failed to read the &#39;selectionDirection&#39; property from &#39;HTMLInputElement&#39;: The input element&#39;s type (&#39;hidden&#39;) does not support selection.
  6. Python For Data Analysis -- Pandas
  7. Android--输入自动提示AutoCompleteTextView
  8. Delphi VclSkin使用教程
  9. IOS ARC与非ARC混合编译
  10. Spring 4 Ehcache Configuration Example with @Cacheable Annotation
  11. error: device not found - waiting for device -
  12. spring学习总结(mybatis,事务,测试JUnit4,日志log4j&amp;slf4j,定时任务quartz&amp;spring-task,jetty,Restful-jersey等)
  13. Javascript Jquery 中的数组定义与操作_子木玲_新浪博客
  14. koahub.js 0.09 发布,新增钩子机制
  15. electron开发客户端注意事项(兼开源个人知识管理工具“想学吗”)
  16. nexus 10 救砖 安装lineage OS 15 并 root
  17. PBRT笔记(10)——体积散射
  18. 第15月第29天 ffmpeg AVERROR_EOF
  19. 分词、词性标注POS等学习【转载】
  20. 百度GIS API使用

热门文章

  1. Debian系统软件安装
  2. selenium+java+eclipse web项目自动化测试环境搭建
  3. python selenium 实战涉及很多知识点
  4. C++之用程序理解浅拷贝
  5. C# async await的使用
  6. PTA(Basic Level)1036.跟奥巴马一起编程
  7. Java中this与super的区别
  8. CF39H 【Multiplication Table】
  9. Java设计模式七种写法
  10. this全面解析&lt;转&gt;