算法基础 - 2-sat问题
来源:互联网 发布:蕲春农村淘宝 编辑:程序博客网 时间:2024/05/18 02:45
2-SAT问题
这个问题其实我们平时早就遇到过,只是从来没有认真的去思考这个问题的解法。这个在我们理解的时候,一般都是按照一个点开始,可以就继续,不可以就停止。
例子问题
例如我们有10个球,每个球都是编号好的,从:1 - 10
这10个球,我们要从中拿出5个球,有以下要求:
并且选了1
就不能选择3
号球,选择了2
号就不能选择4
号球,选择了5
号就不能选择6
号。
但是这里面有个规则:{1, 2}
不能同时存在。同理{3, 4}, {5 , 6}
也不能存在。
这个问题很明了了,怎么解决呢?
最简单的就是枚举,首先选择一个球,看是否有规则,没有就选择下一个,有规则就按照规则选,不可以了,就回溯,一直到发现一个可以的情况,或者所有都不可以的时候,就有答案了。
可是这个方法是在太耗费时间了。更简单的办法,也就是利用图论的只是来解决。
下面是思想:
首先我们看第一个规则,
1 3
不能共存,那么这个时候可以得知,因为3 4
必须选择一个,那么假如我们选择了1
,就必须选择4
了,这样我们就知道了一个边,就是1 -> 4
这个边的意义就是,选择了1
就必须选择4
。那么假如我们选择的是3
呢?那么另外一个就必须选择2
。这个边就是3 -> 2
了。依次类推,我们可以得到下面的图:
这样我们就得到了一个有向图,这个有向图的每条边都代表了选择了一个点,那么同时也要选择它指向的点。如果这个点是孤立的点,例如图中的7 8,那么就随便选择。那么怎么才算无解呢?
两个不相容的点,处在同一个环内,或者更通俗的说是,强连通图内。,就是无解的。
解法
上面通过例子已经讲解了如何解决这个问题:
- 构造有向图,这个有向图是一个表示了选择了一个点,一定要选择它能够到达的点的图。
- 对这个图求强连通图。
- 假如有两个点处在同一个强连通图内,这两个点是必须只能选择一个的一组内的点,就不可以。
- 否则可以
求强连通图的办法是Tarjan算法:传送门: Tarjan算法这是我之前博客里写的。
代码实现
下面这个代码是解决一个问题:
现在有一堆开关,1 2 3 4 5 ... n
这么多,每个开关只有开关两个状态,现在要求,某些开关,不能同时开,或者不能同时关。
求解是否有这么一个状态,满足所有要求。
代码:
#include <iostream>#include <cstring>#include <string>#include <vector>#include <stack>using namespace std;#ifndef MAXNODE#define MAXNODE 20005#endifint flag[MAXNODE] = {0};int dfn[MAXNODE] = {0};int low[MAXNODE] = {0};int tpArr[MAXNODE] = {0};int tpNum = 0;int _index = 0;vector<int> graph[MAXNODE];stack<int> st;void tarjan(int n){ st.push(n); flag[n] = 1; dfn[n] = ++_index; low[n] = _index; for (int i = 0; i < graph[n].size(); i++) { int cur = graph[n][i]; if (dfn[cur] == 0) { tarjan(cur); low[n] = min(low[n], low[cur]); }else{ if (flag[cur] == 1) { low[n] = min(low[n], dfn[cur]); } } } if (dfn[n] == low[n]) { tpNum++; do{ n = st.top(); st.pop(); flag[n] = 0; tpArr[n] = tpNum; }while(dfn[n] != low[n]); }}void addNode(int n1, int n2){ if ((n1&1) > 0) { graph[n1].push_back(n2+1); graph[n2].push_back(n1+1); }else{ graph[n1].push_back(n2-1); graph[n2].push_back(n1-1); }}void transAddNode(int a, int b, int l){ if (l == 1) { addNode(a*2, b*2); }else{ addNode(a*2-1, b*2-1); }}bool judge(int N){ for (int i = 1; i <= N; i++) { if (tpArr[2*i-1] == tpArr[2*i]) { return false; } } return true;}int main(){ int M; cin>>M; //测试组数 while (M--) { int N,T; cin>>N>>T; //N是开关个数,T是规则个数 int a,b,c; for (int i = 0; i < T; i++) { cin>>a>>b>>c; //输入a b c分别代表开关a,开关b,已经开关状态c只有(0/1),表示开关a,b不能同时处于状态c transAddNode(a, b, c); } for (int i = 1; i <= 2*N; i++) { if (dfn[i] == 0) { tarjan(i); } } if(judge(N)){ cout<<"Yes"<<endl; }else{ cout<<"No"<<endl; } for (int i = 1; i <= 2*N;i++) { flag[i] = 0; dfn[i] = 0; low[i] = 0; graph[i].clear(); } _index = 0; } return 0;}
- 算法基础 - 2-sat问题
- 2-SAT问题及其算法
- hdu1824 基础2sat
- 2-SAT算法
- 【2-SAT】2sat问题小结
- 2-SAT问题
- 2-SAT 问题
- 2-sat问题
- 2-sat 问题 模板
- 2-sat问题
- 2-sat问题总结
- 2-sat问题
- 2-sat问题
- 2-sat问题
- 2-SAT 问题
- 2-SAT问题
- 2-sat问题
- 2-SAT问题
- Easy-题目42:223. Rectangle Area
- 《剑指offer》——替换空格
- numpy学习笔记三:numpy文件读写与常用统计方法
- C#用DataTable实现Group by数据统计
- Ubuntu QT下加载程序时提示“system”编码解码无法编辑的解决
- 算法基础 - 2-sat问题
- Jsonp解决ajax跨域问题
- JQuery选择器中的子元素选择器
- Jsoup解析html的基本用法
- 1054. The Dominant Color (20)
- 使用Hadoop Streaming Image进行图像分类 classification with Hadoop Streaming
- ssl例6(未完成)
- Easy-题目43:190. Reverse Bits
- 【HDU】 1397 Goldbach's Conjecture