博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Luogu P4171 [JSOI2010]满汉全席 2-sat
阅读量:6526 次
发布时间:2019-06-24

本文共 2675 字,大约阅读时间需要 8 分钟。

终于搞懂了\(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 
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
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"); }}

转载于:https://www.cnblogs.com/maomao9173/p/10991018.html

你可能感兴趣的文章
DZ!NT论坛 3.6.711删除用户各种错解决方案
查看>>
Python的函数参数传递:传值?引用?
查看>>
[转]分享2011年8个最新的jQuery Mobile在线教程
查看>>
android call require api level
查看>>
Mac下android环境搭建
查看>>
创建Visual Studio项目模版向导的几篇参考文章
查看>>
深入浅出SQL Server Replication第一篇:走近Replication(上)
查看>>
[TopCoder][SRM] SRM 562 DIV 2
查看>>
SQLSERVER是怎麽通过索引和统计信息来找到目标数据的(第一篇)
查看>>
简明 Vim 练级攻略 | 酷壳 - CoolShell.cn
查看>>
LocalAlloc,VirtualAlloc,malloc,new的异同
查看>>
回调函数
查看>>
win7 x64 jdk1.7.0_51
查看>>
45 Useful Oracle Queries--ref
查看>>
这些开源项目,你都知道吗?(持续更新中...)[原创]
查看>>
linux中利用iptables+geoip过滤指定IP
查看>>
在myeclipse中写sql语句的细节问题
查看>>
使用ShellExecute打开目标文件所在文件夹并选中目标文件
查看>>
Lombok简化Java代码的好工具
查看>>
HDU 4614 Vases and Flowers (2013多校2 1004 线段树)
查看>>