zoukankan      html  css  js  c++  java
  • 2sat学习笔记

    介绍

    若干个类似 i or j = 1 的方程组成的方程组,寻找它的可行解的问题,就是2sat问题。方程中未知数个数为n就是n-sat问题。当n大于2时,这个问题是np难问题,因此主要解决的是2-sat问题。

    原理

    对于i or j = 1这个等式,我们可以得到:

    1. i=0 -> j=1
    2. j=0 -> i=1

    这就描述了一种关系。将一个未知量拆成真和假两个状态点,就可以建图了。如果用i代表真,i'代表假,i or j = 1可以表示为:

    1. i' -> j
    2. j' -> i

    求解的方法有两种:dfs和tarjan

    dfs

    选择一个未处理的结点,先选真开始,dfs遍历。如果遍历过程中存在i和i'同时被选到,说明矛盾,换成选假开始。如果还是矛盾,说明无解;否则继续处理剩下结点,直到全部节点都选到,找到一组可行解。

    由于图的对称性,可以保证算法正确性(若存在i->j,必有j'->i')。

    int head[N];
    edge ed[M];
    bool mark[N];
    stack<int> st;
    bool dfs(int p) {
    	if(mark[p ^ 1]) return false;
    	if(mark[p]) return true;
    	mark[p] = true;
    	st.push(p);
    	for(int e = head[p]; e; e = ed[e].ne) {
    		if(!dfs(ed[e].nt)) return false; 
    	}
    	return true;
    }
    
    int main() {
    	bool ok = true;
    	for(int i = 0; i < 2 * m; i += 2) {
    		if(!mark[i] && !mark[i ^ 1]) {
    			while(!st.empty()) st.pop();
    			if(!dfs(i)) {
    				while(!st.empty()) {
    					int cur = st.top();
    					st.pop();
    					mark[cur] = false;
    				}
    				if(!dfs(i ^ 1)) {
    					ok = false;
    					break;
    				}
    			}
    		}
    	}
    	if(ok) cout << "YES" << endl;
    	else cout << "NO" << endl;
    }
    
  • 相关阅读:
    dayⅦ:元组、字典的其他操作+集合类型
    dayⅥ:作业
    dayⅥ:字符串操作+列表操作
    dayⅣ:赋值运算+if判断
    dayⅣ:赋值运算+if判断作业
    dayⅢ、基本数据类型+运算符
    爬虫解析bs4
    爬虫请求库之requests库
    爬虫原理
    各主流Linux系统解决方案pip安装mysqlclient报错
  • 原文地址:https://www.cnblogs.com/limil/p/14510959.html
Copyright © 2011-2022 走看看