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 = 16005; 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^1] = B;ans[cnt++]=u;//记录染了哪些,以便失败后把颜色改回来 for(int i=0;i<G[u].size();i++) if (!dfs(G[u][i])) return false; return true; } bool _solve() { int i, j; memset(col,0,sizeof(col)); for (i=0; i<n; i++){ if (col[i]) continue; cnt=0; if (!dfs(i)){ for (j=0;j<cnt;j++){ col[ans[j]]=W;//漂白 col[ans[j]^1]=W;//漂白 } if (!dfs(i^1)) return false;//2-sat失败 } } return true; } int main() { int i,a,b; while (~scanf("%d %d",&n, &m)){ n<<=1; for(i=0;i<=n;i++) G[i].clear(); while (m--){ scanf("%d %d",&a, &b); a--;b--; G[a].push_back(b^1); G[b].push_back(a^1); } if (_solve()){ for (i=0; i<n; i++) if(col[i] == R) printf("%d\n",i+1); } else printf("NIE\n"); } return 0; }