【整理】2-SAT
2-satisfiability,我们一般将其缩写为 2-sat。
了解全名有助于我们对这个算法的理解。 百度翻译:‘satisfiability’---“可满足性,适定性”。
由于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。去了一个,另一个就不能去,每个党派(集合)都存在这样的关系。
【选择限制】 是存在仇恨的代表,并不是所有党派或者代表都存在这样的关系。
附上代码和注释
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <vector>
- using namespace std;
- #define R 1//red 为ok
- #define B 2//black 访问过但不ok
- #define W 0//white 待染色
- const int maxn = ;
- vector<int>G[maxn];
- int cnt,col[maxn],ans[maxn],n,m;
- bool dfs(int u)
- {
- if (col[u] == B) return false;
- if (col[u] == R) return true;
- col[u] = R;col[u^] = B;ans[cnt++]=u;//记录染了哪些,以便失败后把颜色改回来
- for(int i=;i<G[u].size();i++)
- if (!dfs(G[u][i])) return false;
- return true;
- }
- bool _solve()
- {
- int i, j;
- memset(col,,sizeof(col));
- for (i=; i<n; i++){
- if (col[i]) continue;
- cnt=;
- if (!dfs(i)){
- for (j=;j<cnt;j++){
- col[ans[j]]=W;//漂白
- col[ans[j]^]=W;//漂白
- }
- if (!dfs(i^)) return false;//2-sat失败
- }
- }
- return true;
- }
- int main()
- {
- int i,a,b;
- while (~scanf("%d %d",&n, &m)){
- n<<=;
- for(i=;i<=n;i++) G[i].clear();
- while (m--){
- scanf("%d %d",&a, &b);
- a--;b--;
- G[a].push_back(b^);
- G[b].push_back(a^);
- }
- if (_solve()){
- for (i=; i<n; i++)
- if(col[i] == R)
- printf("%d\n",i+);
- }
- else printf("NIE\n");
- }
- return ;
- }
【例二】
(HDU1824):集训是辛苦的,道路是坎坷的,休息还是必须的。经过一段时间的训练,lcy决定让大家回家放松一下,但是训练还是得照常进行,lcy想出了如下回家规定,每一个队(三人一队)或者队长留下或者其余两名队员同时留下;每一对队员,如果队员A留下,则队员B必须回家休息下,或者B留下,A回家。由于今年集训队人数突破往年同期最高记录,管理难度相当大,lcy也不知道自己的决定是否可行,所以这个难题就交给你了,呵呵,好处嘛~,免费**漂流一日。
【不相容限制】 对于每个人,留或者去,二选一;
【选择限制】 对于一对人,二留一;对于一队人,队员或队长不能同时离开。
®:例二有三个限制,如果没有选择好哪个是不相容限制,很可能给作图造成困难,最后爆炸。
(每次先选小的一个。保证了字典序最小)
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <vector>
- using namespace std;
- #define R 1
- #define B 2
- #define W 0
- const int maxn = ;
- vector<int>G[maxn];
- int cnt,col[maxn],ans[maxn],n,m;
- bool _dfs(int u)
- {
- if (col[u] == B) return false;
- if (col[u] == R) return true;
- col[u] = R;col[u^] = B;ans[cnt++]=u;
- for(int i=;i<G[u].size();i++)
- if (!_dfs(G[u][i])) return false;
- return true;
- }
- bool _solve()
- {
- int i, j;
- memset(col,,sizeof(col));
- for (i=; i<n*; i++){
- if (col[i]) continue;
- cnt=;
- if (!_dfs(i)){
- for (j=;j<cnt;j++){
- col[ans[j]]=W;
- col[ans[j]^]=W;
- }
- if (!_dfs(i^)) return false;
- }
- }
- return true;
- }
- int main()
- {
- int i,a,b,c;
- while (~scanf("%d %d",&n, &m)){
- for(i=;i<n*;i++) G[i].clear();
- for(i=;i<=n;i++){
- scanf("%d%d%d",&a,&b,&c);
- a*=;b*=;c*=;
- G[a^].push_back(b);
- G[a^].push_back(c);
- G[b^].push_back(a);
- G[c^].push_back(a);
- }
- for(i=;i<=m;i++){
- scanf("%d%d",&a,&b);
- a*=;b*=;
- G[a].push_back(b^);
- G[b].push_back(a^);
- }
- if (_solve()) printf("yes\n");
- else printf("no\n");
- }
- return ;
- }
【例三】
(hiho1467):有一场音乐会,分为上午、下午两场进行,主办方指定了n首歌让乐队进行演唱。每首歌只会被演唱一次,要么在上午要么在下午。参加音乐会的嘉宾们对于歌曲的演唱时间有一些要求。具体来说,每位嘉宾会指定两首歌曲的演唱时间(上午或者下午)。如果最后实际的演出安排中,两首歌都没有达到嘉宾的要求,那么嘉宾就会对音乐节不滿意。如嘉宾A的要求是上午《我的滑板鞋》和下午《忐忑》,而最后的演出中上午没有《我的滑板鞋》只有《忐忑》,下午没有《忐忑》只有《我的滑板鞋》,那么嘉宾A是不满意的。
音乐节主办方自然希望使所有嘉宾满意,但主办方后来发现有可能不存在一种歌曲的安排方案满足所有嘉宾,所以他们希望你判断一下这种情况是否会发生。
【不相容限制】 对于每首歌,上午或者下午,二选一。(没有不相容对应的点。拆点,假设上午是i,下午是i+n)
【选择限制】 对于每个观众,至少要完成一个要求。
- #include<cstdio>
- #include<cstdlib>
- #include<cstring>
- #include<iostream>
- #include<algorithm>
- #include<vector>
- using namespace std;
- vector<int>G[];
- int n,m,col[],ans[],cnt;
- const int M=;
- const int H=;
- const int W=;
- int read()
- {
- char c=getchar();
- int s,a=;
- while(c!='h'&&c!='m') c=getchar();
- if(c=='h') a=n;
- scanf("%d",&s);
- return s+a;
- }
- int controt(int u)
- {
- if(u>n) return u-n;
- return u+n;
- }
- bool bfs(int u)
- {
- if(col[u]==M) return true;
- if(col[u]==H) return false;
- col[u]=M;col[controt(u)]=H;ans[++cnt]=u;
- for(int i=;i<G[u].size();i++)
- if(!bfs(G[u][i])) return false;
- return true;
- }
- bool find()
- {
- memset(col,,sizeof(col));
- for(int i=;i<=n+n;i++){
- if(col[i]) continue;
- cnt=;
- if(!bfs(i)){
- for(int j=;j<=cnt;j++) {
- col[ans[j]]=W;
- col[controt(ans[j])]=W;
- }
- cnt=;
- if(!bfs(controt(i))) return false;
- }
- }
- return true;
- }
- int main()
- {
- int i,T,u,v;
- scanf("%d",&T);
- while(T--){
- scanf("%d%d",&n,&m);
- for(i=;i<=n+n;i++) G[i].clear();
- for(i=;i<=m;i++){
- u=read();
- v=read();
- G[u].push_back(controt(v));
- G[v].push_back(controt(u));
- }
- if(find()) printf("GOOD\n");
- else printf("BAD\n");
- }
- return ;
- }
【例四】
(hdu1815):有n个牛棚, 还有两个中转站S1和S2, S1和S2用一条路连接起来。 为了使得任意牛棚两个都可以有道路联通,现在要让每个牛棚都连接一条路到S1或者S2。有a对牛棚互相有仇恨,所以不能让他们的路连接到同一个中转站。还有b对牛棚互相喜欢,所以他们的路必须连到同一个中专站。道路的长度是两点的曼哈顿距离。问最小的任意两牛棚间的距离中的最大值是多少?
【二分】假定ans=x
【不相容限制】 a,b选择特定的的S,若不满足dis<=x,则相排斥。
- #include<cstdio>
- #include<cstdlib>
- #include<iostream>
- #include<cstring>
- #include<algorithm>
- #include<vector>
- using namespace std;
- const int maxn=;
- const int B=;
- const int R=;
- const int W=;
- vector<int>G[maxn];
- vector<int>G2[maxn];
- int dis[][maxn],Dis;//Dis是S点,T点
- int x,y,x1,y1,x2,y2,a,b,n,ans;
- int col[maxn],q[maxn],num;
- void init()
- {
- for(int i=;i<=*n;i++) G[i].clear();
- for(int i=;i<=*n;i++) G2[i].clear();
- ans=-;
- }
- void scan()
- {
- int i;
- scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
- Dis=abs(x1-x2)+abs(y1-y2);
- for(i=;i<=n;i++){
- scanf("%d%d",&x,&y);
- dis[][i]=abs(x-x1)+abs(y-y1);
- dis[][i]=abs(x-x2)+abs(y-y2);
- }
- for(i=;i<=a;i++){
- scanf("%d%d",&x,&y);
- G[x].push_back(y+n);
- G[x+n].push_back(y);
- G[y].push_back(x+n);
- G[y+n].push_back(x);
- }
- for(i=;i<=b;i++){
- scanf("%d%d",&x,&y);
- G[x].push_back(y);
- G[y].push_back(x);
- G[x+n].push_back(y+n);
- G[y+n].push_back(x+n);
- }
- }
- bool dfs(int u)
- {
- if(col[u]==R) return false;
- if(col[u]==B) return true;
- col[u]=B;
- col[u>n?u-n:u+n]=R;
- q[++num]=u;
- for(int i=;i<G[u].size();i++) if(!dfs(G[u][i])) return false;
- for(int i=;i<G2[u].size();i++) if(!dfs(G2[u][i])) return false;
- return true;
- }
- bool check(int x)
- {
- int i,j;
- for(i=;i<=n;i++) if(dis[][i]>x&&dis[][i]>x) return false;
- for(i=;i<=*n;i++) G2[i].clear();
- for(i=;i<=*n;i++) col[i]=;
- for(i=;i<=n;i++)
- for(j=i+;j<=n;j++){
- int d1=dis[][i]+dis[][j];
- int d2=dis[][i]+dis[][j]+Dis;
- int d3=dis[][i]+dis[][j];
- int d4=dis[][i]+dis[][j]+Dis;
- if(d1>x&&d2>x&&d3>x&&d4>x) return false;
- if(d1>x){
- G2[i].push_back(j+n);
- G2[j].push_back(i+n);
- }
- if(d2>x){
- G2[i].push_back(j);
- G2[j+n].push_back(i+n);
- }
- if(d3>x){
- G2[i+n].push_back(j);
- G2[j+n].push_back(i);
- }
- if(d4>x){
- G2[i+n].push_back(j+n);
- G2[j].push_back(i);
- }
- }
- for(i=;i<=*n;i++){
- if(col[i]) continue;
- num=;
- if(!dfs(i)){
- for(j=;j<=num;j++) {
- col[q[j]>n?q[j]-n:q[j]+n]=W;
- col[q[j]]=W;
- }
- if(!dfs(i>n?i-n:i+n)) return false;
- }
- }
- return true;
- }
- int main()
- {
- while(~scanf("%d%d%d",&n,&a,&b)){
- init();
- int L=,R=;
- scan();
- while(L<=R){
- int mid=(L+R)>>;
- if(check(mid)){ ans=mid;R=mid-;}
- else L=mid+;
- }
- printf("%d\n",ans);
- }
- return ;
- }
本文仅阐述如何寻找不相容限制,然后去建图。
所以代码的优化在这里没有提及,用【缩点】和【拓扑】的优化将在下文补充。
如果你对2-sat有什么新的认识,或者疑问,请留言额。待续。。。
【整理】2-SAT的更多相关文章
- shell常用命令归类整理
shell 命令整理 bash shell 含有许多功能,因此有许多可用的命令:本文档仅罗列了一些常用命令及其使用频率较高的参数.#本文档仅罗列了一些常用命令及其使用频率较高的参数.#vers ...
- Docker学习笔记整理
Docker接触有一段时间了,但是对于Docker的使用可以说是一点不会.现在要在Docker上部署基于Angular开发的页面.只能一点点积累查找的资料,顺手整理一下,方便后面的回顾. 其中用到的资 ...
- 前端必会html知识整理
1.浏览器内核: 1.ie:trident(三叉戟)内核 2.firefox:gecko(壁虎)内核 3.safari:webkit(浏览器核心)内核 ...
- (整理)ubuntu 的 相关知识(来自 鸟哥的私房菜)
1. Linux 文件权限概念 $ ls 察看文件的指令 $ ls -al 出所有的文件详细的权限与属性 (包含隐藏档,就是文件名第一个字符为『 . 』的文件) 在你第一次以root身份登入Linux ...
- MATLAB中文论坛帖子整理(GUI)
MATLAB中文论坛帖子整理(GUI) 目 录 1.GUI新手之——教你读懂GUI的M文件... 10 2.GUI程序中改变current directory引起的问题... 15 3.GUI中 ...
- 笔记整理--玩转robots协议
玩转robots协议 -- 其他 -- IT技术博客大学习 -- 共学习 共进步! - Google Chrome (2013/7/14 20:24:07) 玩转robots协议 2013年2月8日北 ...
- python 基础部分重点复习整理--从意识那天开始进阶--已结
pythonic 风格编码 入门python好博客 进阶大纲 有趣的灵魂 老齐的教程 老齐还整理了很多精华 听说 fluent python + pro python 这两本书还不错! 元组三种遍历, ...
- [转]开源日志库<log4cplus+VS2008使用>整理
转 开源日志库<log4cplus+VS2008使用>整理 转http://pyhcx.blog.51cto.com/713166/143549 一.简介 log4cplus是C+ ...
- JS知识点整理(二)
前言 这是对平时的一些读书笔记和理解进行整理的第二部分,第一部分请前往:JS知识点整理(一).本文包含一些易混淆.遗漏的知识点,也会配上一些例子,也许不是很完整,也许还会有点杂,但也许会有你需要的,后 ...
- 整理一些JavaScript时间处理扩展函数
在JavaScript中,时间处理是经常需要用到的.最近想要慢慢建立自己的代码库,整理了几个之前用到的js处理时间的函数,发出来跟大家分享一下,以后的使用中会不断增加和修改代码库. 把字符串转换为日期 ...
随机推荐
- Python基础(14)_python模块之configparser模块、suprocess
9.configparser模块 模块适用于配置文件的格式与windows ini文件类似,可以包含一个或多个节(section),每个节可以有多个参数(键=值). 常见的软件格式文档格式如下: [D ...
- Web Deploy 安装及问题解决
注意: 站点名称: 服务器上IIS的站点名称. . 我之前这里随便写一直不成功. 返回500..... 用户名, 密码: 这里最好用windows帐号. 问题比较少. 目标URL: 可不写. 可 ...
- C# 学习黑马.Net视频教程,大文件拷贝
设计器代码: namespace 大文件拷贝 { partial class Form1 { /// <summary> /// 必需的设计器变量. /// </summary> ...
- 每天一个Linux命令(49)traceroute命令
traceroute指令让你追踪网络数据包的路由途径,预设数据包大小是40Bytes. (1)用法: 用法: traceroute [参数] [主机] (2)功能: ...
- php数组函数-array_pad()
array_pad()函数向一个数组插入带有指定值的指定数量的元素. array_pad(array,size,value); array:必需.规定数组 size:必需.指定的长度.正数则填补到右侧 ...
- [RK3288][Android6.0] USB OTG模式及切换【转】
本文转载自:https://blog.csdn.net/kris_fei/article/details/78620960 Platform: RK3288 OS: Android 6.0 Kerne ...
- ZooKeeper-znode概念与使用
可以将ZK看作一个具有高可用性特征的文件系统.这个文件系统中没有文件和目录,而是统一使用节点(znode)的概念,称为znode.znode既可以作为保存数据的容器(如同文件),也可以作为保存其他zn ...
- 使用log4j2打印Log,log4j不能打印日志信息,log4j2不能打印日志信息,log4j和logj2,idea控制台信息乱码(文末)
说来惭愧,今天就写了个"hello world",了解了一下log4j的日志. 本来是想在控制台打印个log信息,也是遇到坎坷重重,开始也没去了解log4j就来使用,log4j配置 ...
- JMeter ——Test fragment
fragment 为片段,可以是一个不完整的用例.比如你可以把一个http请求保存为fragment,如果不这样做的话,你是必须先要添加一个测试计划-线程组-http请求的.你可以把某步骤一系列的请求 ...
- Python运行的17个时新手常见错误小结
1)忘记在if , elif , else , for , while , class ,def 声明末尾添加 :(导致“SyntaxError :invalid syntax”) 该错误将发生在类似 ...