2-satisfiability,我们一般将其缩写为 2-sat。

了解全名有助于我们对这个算法的理解。     百度翻译:‘satisfiability’---“可满足性,适定性”。

合取范式可满足性问题(简称SAT问题)是一个NP完全问题。”

由于SAT问题目前是NP问题,所以自然有最大化满足性问题———MAX-SAT。

然后也有最基本的问题,生存or死亡,嫁给我or吃屎———2-SAT。

如果能解决k-sat问题,那么他一定会火,毕竟没有很好的算法去解决,目前我们研究得更多是2-sat。

之前做的两个2-sat题:nmphy的2-sat。第三个是今天做的,整理一下。

-----------------------------------------------------我是分界线----------------------------------------------------------------

浅谈2-sat:(假设读者已经知道了2sat的原理,只是有时会乱,不知道把谁作为点,谁作为边,不知道怎么建图是好)

一般会有两个或者多个限制,要选择其中一个作为不相容限制。

然后其他的条件作为有向图,然后判环:

【关键】:整个算法转化成图的关键就是找好对象,判断出哪个作为不相容限制

如果不相容限制的两个子都不能满足,那么结果为false。

不相容限制】:n个被选择,每个是‘真’or‘假’,代表二者不能同时存在。

选择限制】:m个要求,一般牵涉到两个不相容限制。

判断是哪种限制:不相容限制再每个集合都存在,而选择限制不是。

【例一】

(HDU1814):题目大意:一国有n个党派,每个党派在议会中都有2个代表,现要组建和平委员会,要从每个党派在议会的代表中选出1人,一共n人组成和平委员会。已知有一些代表之间存在仇恨,也就是说他们不能同时被选为和平委员会的成员,现要你判断满足要求的和平委员会能否创立?如果能,请任意给出一种方案。

【不相容限制】 是每个党派的代表,设为1,2。去了一个,另一个就不能去,每个党派(集合)都存在这样的关系。

            【选择限制】     是存在仇恨的代表,并不是所有党派或者代表都存在这样的关系。

附上代码和注释

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <vector>
  5. using namespace std;
  6. #define R 1//red 为ok
  7. #define B 2//black 访问过但不ok
  8. #define W 0//white 待染色
  9. const int maxn = ;
  10. vector<int>G[maxn];
  11. int cnt,col[maxn],ans[maxn],n,m;
  12. bool dfs(int u)
  13. {
  14. if (col[u] == B) return false;
  15. if (col[u] == R) return true;
  16. col[u] = R;col[u^] = B;ans[cnt++]=u;//记录染了哪些,以便失败后把颜色改回来
  17. for(int i=;i<G[u].size();i++)
  18. if (!dfs(G[u][i])) return false;
  19. return true;
  20. }
  21. bool _solve()
  22. {
  23. int i, j;
  24. memset(col,,sizeof(col));
  25. for (i=; i<n; i++){
  26. if (col[i]) continue;
  27. cnt=;
  28. if (!dfs(i)){
  29. for (j=;j<cnt;j++){
  30. col[ans[j]]=W;//漂白
  31. col[ans[j]^]=W;//漂白
  32. }
  33. if (!dfs(i^)) return false;//2-sat失败
  34. }
  35. }
  36. return true;
  37. }
  38. int main()
  39. {
  40. int i,a,b;
  41. while (~scanf("%d %d",&n, &m)){
  42. n<<=;
  43. for(i=;i<=n;i++) G[i].clear();
  44. while (m--){
  45. scanf("%d %d",&a, &b);
  46. a--;b--;
  47. G[a].push_back(b^);
  48. G[b].push_back(a^);
  49. }
  50. if (_solve()){
  51. for (i=; i<n; i++)
  52. if(col[i] == R)
  53. printf("%d\n",i+);
  54. }
  55. else printf("NIE\n");
  56. }
  57. return ;
  58. }

【例二】

(HDU1824):集训是辛苦的,道路是坎坷的,休息还是必须的。经过一段时间的训练,lcy决定让大家回家放松一下,但是训练还是得照常进行,lcy想出了如下回家规定,每一个队(三人一队)或者队长留下或者其余两名队员同时留下;每一对队员,如果队员A留下,则队员B必须回家休息下,或者B留下,A回家。由于今年集训队人数突破往年同期最高记录,管理难度相当大,lcy也不知道自己的决定是否可行,所以这个难题就交给你了,呵呵,好处嘛~,免费**漂流一日。

 【不相容限制】 对于每个人,留或者去,二选一;

           【选择限制】     对于一对人,二留一;对于一队人,队员或队长不能同时离开。

            ®:例二有三个限制,如果没有选择好哪个是不相容限制,很可能给作图造成困难,最后爆炸。

(每次先选小的一个。保证了字典序最小)

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <vector>
  5. using namespace std;
  6. #define R 1
  7. #define B 2
  8. #define W 0
  9. const int maxn = ;
  10. vector<int>G[maxn];
  11. int cnt,col[maxn],ans[maxn],n,m;
  12. bool _dfs(int u)
  13. {
  14. if (col[u] == B) return false;
  15. if (col[u] == R) return true;
  16. col[u] = R;col[u^] = B;ans[cnt++]=u;
  17. for(int i=;i<G[u].size();i++)
  18. if (!_dfs(G[u][i])) return false;
  19. return true;
  20. }
  21. bool _solve()
  22. {
  23. int i, j;
  24. memset(col,,sizeof(col));
  25. for (i=; i<n*; i++){
  26. if (col[i]) continue;
  27. cnt=;
  28. if (!_dfs(i)){
  29. for (j=;j<cnt;j++){
  30. col[ans[j]]=W;
  31. col[ans[j]^]=W;
  32. }
  33. if (!_dfs(i^)) return false;
  34. }
  35. }
  36. return true;
  37. }
  38. int main()
  39. {
  40. int i,a,b,c;
  41. while (~scanf("%d %d",&n, &m)){
  42. for(i=;i<n*;i++) G[i].clear();
  43. for(i=;i<=n;i++){
  44. scanf("%d%d%d",&a,&b,&c);
  45. a*=;b*=;c*=;
  46. G[a^].push_back(b);
  47. G[a^].push_back(c);
  48. G[b^].push_back(a);
  49. G[c^].push_back(a);
  50. }
  51. for(i=;i<=m;i++){
  52. scanf("%d%d",&a,&b);
  53. a*=;b*=;
  54. G[a].push_back(b^);
  55. G[b].push_back(a^);
  56. }
  57. if (_solve()) printf("yes\n");
  58. else printf("no\n");
  59. }
  60. return ;
  61. }

【例三】

(hiho1467):有一场音乐会,分为上午、下午两场进行,主办方指定了n首歌让乐队进行演唱。每首歌只会被演唱一次,要么在上午要么在下午。参加音乐会的嘉宾们对于歌曲的演唱时间有一些要求。具体来说,每位嘉宾会指定两首歌曲的演唱时间(上午或者下午)。如果最后实际的演出安排中,两首歌都没有达到嘉宾的要求,那么嘉宾就会对音乐节不滿意。如嘉宾A的要求是上午《我的滑板鞋》和下午《忐忑》,而最后的演出中上午没有《我的滑板鞋》只有《忐忑》,下午没有《忐忑》只有《我的滑板鞋》,那么嘉宾A是不满意的。

音乐节主办方自然希望使所有嘉宾满意,但主办方后来发现有可能不存在一种歌曲的安排方案满足所有嘉宾,所以他们希望你判断一下这种情况是否会发生。

【不相容限制】 对于每首歌,上午或者下午,二选一。(没有不相容对应的点。拆点,假设上午是i,下午是i+n

【选择限制】 对于每个观众,至少要完成一个要求。

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<algorithm>
  6. #include<vector>
  7. using namespace std;
  8. vector<int>G[];
  9. int n,m,col[],ans[],cnt;
  10. const int M=;
  11. const int H=;
  12. const int W=;
  13. int read()
  14. {
  15. char c=getchar();
  16. int s,a=;
  17. while(c!='h'&&c!='m') c=getchar();
  18. if(c=='h') a=n;
  19. scanf("%d",&s);
  20. return s+a;
  21. }
  22. int controt(int u)
  23. {
  24. if(u>n) return u-n;
  25. return u+n;
  26. }
  27. bool bfs(int u)
  28. {
  29. if(col[u]==M) return true;
  30. if(col[u]==H) return false;
  31. col[u]=M;col[controt(u)]=H;ans[++cnt]=u;
  32. for(int i=;i<G[u].size();i++)
  33. if(!bfs(G[u][i])) return false;
  34. return true;
  35. }
  36. bool find()
  37. {
  38. memset(col,,sizeof(col));
  39. for(int i=;i<=n+n;i++){
  40. if(col[i]) continue;
  41. cnt=;
  42. if(!bfs(i)){
  43. for(int j=;j<=cnt;j++) {
  44. col[ans[j]]=W;
  45. col[controt(ans[j])]=W;
  46. }
  47. cnt=;
  48. if(!bfs(controt(i))) return false;
  49. }
  50. }
  51. return true;
  52. }
  53. int main()
  54. {
  55. int i,T,u,v;
  56. scanf("%d",&T);
  57. while(T--){
  58. scanf("%d%d",&n,&m);
  59. for(i=;i<=n+n;i++) G[i].clear();
  60. for(i=;i<=m;i++){
  61. u=read();
  62. v=read();
  63. G[u].push_back(controt(v));
  64. G[v].push_back(controt(u));
  65. }
  66. if(find()) printf("GOOD\n");
  67. else printf("BAD\n");
  68. }
  69. return ;
  70. }

【例四】

(hdu1815):有n个牛棚, 还有两个中转站S1和S2, S1和S2用一条路连接起来。 为了使得任意牛棚两个都可以有道路联通,现在要让每个牛棚都连接一条路到S1或者S2。有a对牛棚互相有仇恨,所以不能让他们的路连接到同一个中转站。还有b对牛棚互相喜欢,所以他们的路必须连到同一个中专站。道路的长度是两点的曼哈顿距离。问最小的任意两牛棚间的距离中的最大值是多少?

【二分】假定ans=x

【不相容限制】 a,b选择特定的的S,若不满足dis<=x,则相排斥。

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<iostream>
  4. #include<cstring>
  5. #include<algorithm>
  6. #include<vector>
  7. using namespace std;
  8. const int maxn=;
  9. const int B=;
  10. const int R=;
  11. const int W=;
  12. vector<int>G[maxn];
  13. vector<int>G2[maxn];
  14. int dis[][maxn],Dis;//Dis是S点,T点
  15. int x,y,x1,y1,x2,y2,a,b,n,ans;
  16. int col[maxn],q[maxn],num;
  17. void init()
  18. {
  19. for(int i=;i<=*n;i++) G[i].clear();
  20. for(int i=;i<=*n;i++) G2[i].clear();
  21. ans=-;
  22. }
  23. void scan()
  24. {
  25. int i;
  26. scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
  27. Dis=abs(x1-x2)+abs(y1-y2);
  28. for(i=;i<=n;i++){
  29. scanf("%d%d",&x,&y);
  30. dis[][i]=abs(x-x1)+abs(y-y1);
  31. dis[][i]=abs(x-x2)+abs(y-y2);
  32. }
  33. for(i=;i<=a;i++){
  34. scanf("%d%d",&x,&y);
  35. G[x].push_back(y+n);
  36. G[x+n].push_back(y);
  37. G[y].push_back(x+n);
  38. G[y+n].push_back(x);
  39. }
  40. for(i=;i<=b;i++){
  41. scanf("%d%d",&x,&y);
  42. G[x].push_back(y);
  43. G[y].push_back(x);
  44. G[x+n].push_back(y+n);
  45. G[y+n].push_back(x+n);
  46. }
  47.  
  48. }
  49. bool dfs(int u)
  50. {
  51. if(col[u]==R) return false;
  52. if(col[u]==B) return true;
  53. col[u]=B;
  54. col[u>n?u-n:u+n]=R;
  55. q[++num]=u;
  56. for(int i=;i<G[u].size();i++) if(!dfs(G[u][i])) return false;
  57. for(int i=;i<G2[u].size();i++) if(!dfs(G2[u][i])) return false;
  58. return true;
  59. }
  60. bool check(int x)
  61. {
  62. int i,j;
  63. for(i=;i<=n;i++) if(dis[][i]>x&&dis[][i]>x) return false;
  64. for(i=;i<=*n;i++) G2[i].clear();
  65. for(i=;i<=*n;i++) col[i]=;
  66. for(i=;i<=n;i++)
  67. for(j=i+;j<=n;j++){
  68. int d1=dis[][i]+dis[][j];
  69. int d2=dis[][i]+dis[][j]+Dis;
  70. int d3=dis[][i]+dis[][j];
  71. int d4=dis[][i]+dis[][j]+Dis;
  72. if(d1>x&&d2>x&&d3>x&&d4>x) return false;
  73. if(d1>x){
  74. G2[i].push_back(j+n);
  75. G2[j].push_back(i+n);
  76. }
  77. if(d2>x){
  78. G2[i].push_back(j);
  79. G2[j+n].push_back(i+n);
  80. }
  81. if(d3>x){
  82. G2[i+n].push_back(j);
  83. G2[j+n].push_back(i);
  84. }
  85. if(d4>x){
  86. G2[i+n].push_back(j+n);
  87. G2[j].push_back(i);
  88. }
  89. }
  90. for(i=;i<=*n;i++){
  91. if(col[i]) continue;
  92. num=;
  93. if(!dfs(i)){
  94. for(j=;j<=num;j++) {
  95. col[q[j]>n?q[j]-n:q[j]+n]=W;
  96. col[q[j]]=W;
  97. }
  98. if(!dfs(i>n?i-n:i+n)) return false;
  99. }
  100. }
  101. return true;
  102. }
  103. int main()
  104. {
  105. while(~scanf("%d%d%d",&n,&a,&b)){
  106. init();
  107. int L=,R=;
  108. scan();
  109. while(L<=R){
  110. int mid=(L+R)>>;
  111. if(check(mid)){ ans=mid;R=mid-;}
  112. else L=mid+;
  113. }
  114. printf("%d\n",ans);
  115. }
  116. return ;
  117. }

本文仅阐述如何寻找不相容限制,然后去建图。

所以代码的优化在这里没有提及,用【缩点】【拓扑】的优化将在下文补充。

如果你对2-sat有什么新的认识,或者疑问,请留言额。待续。。。

【整理】2-SAT的更多相关文章

  1. shell常用命令归类整理

    shell 命令整理     bash shell 含有许多功能,因此有许多可用的命令:本文档仅罗列了一些常用命令及其使用频率较高的参数.#本文档仅罗列了一些常用命令及其使用频率较高的参数.#vers ...

  2. Docker学习笔记整理

    Docker接触有一段时间了,但是对于Docker的使用可以说是一点不会.现在要在Docker上部署基于Angular开发的页面.只能一点点积累查找的资料,顺手整理一下,方便后面的回顾. 其中用到的资 ...

  3. 前端必会html知识整理

    1.浏览器内核:         1.ie:trident(三叉戟)内核         2.firefox:gecko(壁虎)内核         3.safari:webkit(浏览器核心)内核 ...

  4. (整理)ubuntu 的 相关知识(来自 鸟哥的私房菜)

    1. Linux 文件权限概念 $ ls 察看文件的指令 $ ls -al 出所有的文件详细的权限与属性 (包含隐藏档,就是文件名第一个字符为『 . 』的文件) 在你第一次以root身份登入Linux ...

  5. MATLAB中文论坛帖子整理(GUI)

    MATLAB中文论坛帖子整理(GUI) 目   录  1.GUI新手之——教你读懂GUI的M文件... 10 2.GUI程序中改变current directory引起的问题... 15 3.GUI中 ...

  6. 笔记整理--玩转robots协议

    玩转robots协议 -- 其他 -- IT技术博客大学习 -- 共学习 共进步! - Google Chrome (2013/7/14 20:24:07) 玩转robots协议 2013年2月8日北 ...

  7. python 基础部分重点复习整理--从意识那天开始进阶--已结

    pythonic 风格编码 入门python好博客 进阶大纲 有趣的灵魂 老齐的教程 老齐还整理了很多精华 听说 fluent python + pro python 这两本书还不错! 元组三种遍历, ...

  8. [转]开源日志库<log4cplus+VS2008使用>整理

    转 开源日志库<log4cplus+VS2008使用>整理 转http://pyhcx.blog.51cto.com/713166/143549 一.简介     log4cplus是C+ ...

  9. JS知识点整理(二)

    前言 这是对平时的一些读书笔记和理解进行整理的第二部分,第一部分请前往:JS知识点整理(一).本文包含一些易混淆.遗漏的知识点,也会配上一些例子,也许不是很完整,也许还会有点杂,但也许会有你需要的,后 ...

  10. 整理一些JavaScript时间处理扩展函数

    在JavaScript中,时间处理是经常需要用到的.最近想要慢慢建立自己的代码库,整理了几个之前用到的js处理时间的函数,发出来跟大家分享一下,以后的使用中会不断增加和修改代码库. 把字符串转换为日期 ...

随机推荐

  1. Python基础(14)_python模块之configparser模块、suprocess

    9.configparser模块 模块适用于配置文件的格式与windows ini文件类似,可以包含一个或多个节(section),每个节可以有多个参数(键=值). 常见的软件格式文档格式如下: [D ...

  2. Web Deploy 安装及问题解决

    注意: 站点名称:  服务器上IIS的站点名称.  . 我之前这里随便写一直不成功. 返回500..... 用户名, 密码:  这里最好用windows帐号. 问题比较少. 目标URL: 可不写. 可 ...

  3. C# 学习黑马.Net视频教程,大文件拷贝

    设计器代码: namespace 大文件拷贝 { partial class Form1 { /// <summary> /// 必需的设计器变量. /// </summary> ...

  4. 每天一个Linux命令(49)traceroute命令

        traceroute指令让你追踪网络数据包的路由途径,预设数据包大小是40Bytes.     (1)用法:     用法: traceroute [参数] [主机]   (2)功能:     ...

  5. php数组函数-array_pad()

    array_pad()函数向一个数组插入带有指定值的指定数量的元素. array_pad(array,size,value); array:必需.规定数组 size:必需.指定的长度.正数则填补到右侧 ...

  6. [RK3288][Android6.0] USB OTG模式及切换【转】

    本文转载自:https://blog.csdn.net/kris_fei/article/details/78620960 Platform: RK3288 OS: Android 6.0 Kerne ...

  7. ZooKeeper-znode概念与使用

    可以将ZK看作一个具有高可用性特征的文件系统.这个文件系统中没有文件和目录,而是统一使用节点(znode)的概念,称为znode.znode既可以作为保存数据的容器(如同文件),也可以作为保存其他zn ...

  8. 使用log4j2打印Log,log4j不能打印日志信息,log4j2不能打印日志信息,log4j和logj2,idea控制台信息乱码(文末)

    说来惭愧,今天就写了个"hello world",了解了一下log4j的日志. 本来是想在控制台打印个log信息,也是遇到坎坷重重,开始也没去了解log4j就来使用,log4j配置 ...

  9. JMeter ——Test fragment

    fragment 为片段,可以是一个不完整的用例.比如你可以把一个http请求保存为fragment,如果不这样做的话,你是必须先要添加一个测试计划-线程组-http请求的.你可以把某步骤一系列的请求 ...

  10. Python运行的17个时新手常见错误小结

    1)忘记在if , elif , else , for , while , class ,def 声明末尾添加 :(导致“SyntaxError :invalid syntax”) 该错误将发生在类似 ...