终于搞懂了\(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\)完全。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int N = 200 + 5;
  4. const int M = 2000 + 5;
  5. struct Graph {
  6. int cnt, head[N];
  7. struct Edge {
  8. int nxt, to;
  9. }e[M];
  10. void clear () {
  11. cnt = -1;
  12. memset (head, -1, sizeof (head));
  13. }
  14. void add_edge (int u, int v) {
  15. e[++cnt] = (Edge) {head[u], v}; head[u] = cnt;
  16. }
  17. stack <int> sta;
  18. int _dfn, _sccid;
  19. int inq[N], dfn[N], low[N], sccid[N];
  20. void Tarjan (int u) {
  21. dfn[u] = low[u] = ++_dfn;
  22. inq[u] = true; sta.push (u);
  23. for (int i = head[u]; ~i; i = e[i].nxt) {
  24. int v = e[i].to;
  25. if (!dfn[v]) {
  26. Tarjan (v);
  27. low[u] = min (low[u], low[v]);
  28. } else if (inq[v]) {
  29. low[u] = min (low[u], dfn[v]);
  30. }
  31. }
  32. if (dfn[u] == low[u]) {
  33. int tmp; ++_sccid;
  34. do {
  35. tmp = sta.top ();
  36. inq[tmp] = false;
  37. sccid[tmp] = _sccid;
  38. sta.pop ();
  39. }while (tmp != u);
  40. }
  41. }
  42. void get_scc (int n) {
  43. _dfn = _sccid = 0;
  44. memset (inq, 0, sizeof (inq));
  45. memset (dfn, 0, sizeof (dfn));
  46. for (int i = 1; i <= n; ++i) {
  47. if (!dfn[i]) Tarjan (i);
  48. }
  49. }
  50. }G;
  51. int T, n, m;
  52. int node (int x, int t) {
  53. return n * t + x;
  54. }
  55. int main () {
  56. // freopen ("data.in", "r", stdin);
  57. cin >> T;
  58. while (T--) {
  59. cin >> n >> m; G.clear ();
  60. for (int i = 1; i <= m; ++i) {
  61. static int u, v, t1, t2;
  62. while (!isalpha (t1 = getchar ())); cin >> u;
  63. while (!isalpha (t2 = getchar ())); cin >> v;
  64. t1 = t1 == 'm' ? 0 : 1;
  65. t2 = t2 == 'm' ? 0 : 1;
  66. G.add_edge (node (u, !t1), node (v, t2));
  67. G.add_edge (node (v, !t2), node (u, t1));
  68. }
  69. G.get_scc (n << 1);
  70. bool succ = true;
  71. for (int i = 1; i <= n; ++i) {
  72. if (G.sccid[node (i, 0)] == G.sccid[node (i, 1)]) {
  73. succ = false; break;
  74. }
  75. }
  76. puts (succ ? "GOOD" : "BAD");
  77. }
  78. }

Luogu P4171 [JSOI2010]满汉全席 2-sat的更多相关文章

  1. LUOGU P4171 [JSOI2010]满汉全席

    传送门 解题思路 2-SAT 裸题. 代码 #include<iostream> #include<cstdio> #include<cstring> #inclu ...

  2. 洛谷 P4171 [JSOI2010]满汉全席 解题报告

    P4171 [JSOI2010]满汉全席 题目描述 满汉全席是中国最丰盛的宴客菜肴,有许多种不同的材料透过满族或是汉族的料理方式,呈现在數量繁多的菜色之中.由于菜色众多而繁杂,只有极少數博学多闻技艺高 ...

  3. 洛谷P4171 [JSOI2010] 满汉全席 [2-SAT,Tarjan]

    题目传送门 满汉全席 题目描述 满汉全席是中国最丰盛的宴客菜肴,有许多种不同的材料透过满族或是汉族的料理方式,呈现在數量繁多的菜色之中.由于菜色众多而繁杂,只有极少數博学多闻技艺高超的厨师能够做出满汉 ...

  4. P4171 [JSOI2010]满汉全席

    简要的学了一下2-sat,然而不会输出方案. 就是个sb模板题啦 // luogu-judger-enable-o2 #include<bits/stdc++.h> #define il ...

  5. [洛谷P4171][JSOI2010]满汉全席

    题目大意:有$n$个点,每个点可以选或不选,有$m$组约束,形如$a,u,b,v$,表示$u=a,v=b$中至少要满足一个条件,问是否存在一组解,多组询问 题解:$2-SAT$,感觉是板子题呀,最后判 ...

  6. P4171 [JSOI2010]满汉全席(2-SAT)

    传送门 2-SAT裸题 把每一道菜拆成两个点分别表示用汉式或满式 连边可以参考板子->这里 然后最尴尬的是我没发现$n<=100$然后化成整数的时候只考虑了$s[1]$结果炸掉了2333 ...

  7. bzoj1823 [JSOI2010]满汉全席(2-SAT)

    1823: [JSOI2010]满汉全席 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1246  Solved: 598[Submit][Status ...

  8. BZOJ 1823: [JSOI2010]满汉全席( 2-sat )

    2-sat...假如一个评委喜好的2样中..其中一样没做, 那另一样就一定要做, 这样去建图..然后跑tarjan. 时间复杂度O((n+m)*K) ------------------------- ...

  9. BZOJ_1823_[JSOI2010]满汉全席_2-sat+tarjan

    BZOJ_1823_[JSOI2010]满汉全席_2-sat 题意:http://www.lydsy.com/JudgeOnline/problem.php?id=1823 分析:一道比较容易看出来的 ...

随机推荐

  1. stack smashing detected解决过程

    在执行程序结束return 0 之后出现上图问题.主要原因是在程序中存在数组越界. 解决方法: 1. 查看定义的结构体内buffer大小,为4096字节 typedef struct { UINT32 ...

  2. SQL Injection(Blind)

    SQL Injection(Blind),即SQL盲注,与一般注入的区别在于,一般的注入攻击者可以直接从页面上看到注入语句的执行结果,而盲注时攻击者通常是无法从显示页面上获取执行结果,甚至连注入语句是 ...

  3. 【Qt开发】QT对话框去掉帮助和关闭按钮 拦截QT关闭窗口的CloseEvent

    建了一个对话框,我不想把边框去掉,只想去掉关闭按钮, setWindowFlags(windowFlags()&~Qt::WindowCloseButtonHint&~Qt::Wind ...

  4. VS2017:"64位调试操作花费的时间比预期要长",无法运行调试解决办法

    关于这个问题网上搜了好久,参考http://www.yishimei123.com/network/685.html这篇文章,最后终于解决了,在此表示非常感谢! 我的环境是:win10+VS2017 ...

  5. 什么是java的线程安全?同步,异步

    线程是比进程更小的执行单位,是在进程基础上进行的进一步划分.所谓多线程是指进程在执行过程中可以产生多个同时存在.同时运行的线程.多进程机制可以合理利用资源,提高程序的运行效率.一个进程至少包含一个线程 ...

  6. [c++] WINAPI

    int WINAPI WINMain 中,WINAPI含义 在windef.h头文件中有如下定义: #define WINAPI __stdcall #define APIENTRY WINAPI 函 ...

  7. python之函数、面向对象

    学习python到了函数这一块进度有所放缓,主要还是想理解透彻,毕竟直觉告诉我函数是python是其中的关键,不管是模块.还是包.或者是库,都是建立在若干个函数定义上面. 章节后面就是关于面向对象编程 ...

  8. python实现更换电脑桌面壁纸,锁屏,文件加密方式

    python实现更换壁纸和锁屏代码 #控制windows系统 import win32api,win32con,win32gui # 可以利用python去调用dll动态库的包.嵌入式开发 from ...

  9. ITCAST-C# 委托

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace _12委 ...

  10. loj 6031「雅礼集训 2017 Day1」字符串

    loj 注意到每次询问串长度都是给定的,并且询问串长\(k*\)询问次数\(q<10^5\),所以这里面一个东西大的时候另一个东西就小,那么考虑对较小的下功夫 如果\(k\le \sqrt{n} ...