tk's blog
  • tk's blog Read Me
  • 算法相关
    • 数据结构
      • 【集训整理】 旋转treap模板
      • 二叉树及相关数据结构的java语言实现
      • 快乐树0x01:AVL树的java实现
      • 快乐树0x02 线段树实现(c++)
      • 链表的Java语言实现
    • 算法
      • DP的背包问题小结-java语言描述
      • 【集训整理】2-SAT问题 模板题
      • 【集训整理】Tarjan算法 模板题
      • 【集训整理】差分约束 模板题
      • 【集训整理】最近公共祖先LCA 模板题
      • 二分查找与二分答案-java实现
      • 动态规划-java语言练习一:暴力DP
      • 快速幂
      • 状态压缩DP-java描述
      • 差分
      • 乘法逆元
    • 题解
      • CFRound-GoodBye2022题解
  • java相关
    • Java与算法竞赛——注意事项摘录
    • java面向对象简要总结 一
    • java面向对象简要总结 三
    • java面向对象简要总结 二
  • 后端相关
    • Linux-Crontab命令
    • Spring Data JPA 使用方法
    • Spring集成Artemis实现JSM的异步消息传递
    • Spring使用自定义配置项
    • MIT6.824分布式系统Lab1.MapReduce笔记
    • MIT6.824分布式系统Lab2-Raft-A笔记
    • MIT6.824分布式系统Lab2-Raft-B笔记
  • 杂谈
    • 杂谈-关于2021
  • 杂项
    • c语言 scanf的返回值
    • 系统设计
  • 计科基础
    • 编译原理
      • 编译原理:词法分析笔记
    • CSAPP 第二章笔记
    • 计算机组成原理笔记
    • CSAPP Lab1. Datalab
    • CSAPP Lab2 Bomblab
  • C++每日一题
    • C++每日一题 Day 1 肥宅水
    • C++每日一题 Day 2 数字反转
    • C++每日一题 Day 3 理五的凡尔赛风气
    • C++每日一题 Day 4 我喜欢这个数
    • C++每日一题 Day 5 数字楼梯
    • C++每日一题 Day 6 插火把
    • C++每日一题 Day 7 贪吃蛇
    • C++每日一题 Day 8 蒙德最强战力
    • C++每日一题 Day 9 璃月七星选举
    • C每日一题 Day 2 肥宅水
    • C每日一题 Day 3 理五的凡尔赛风气
    • C语言每日一题 Day 1 荧妹好感队
由 GitBook 提供支持
在本页
  1. 算法相关
  2. 算法

【集训整理】2-SAT问题 模板题


题面:

m 个约束条件,第 j 个约束条件有四个整数 u,x,v,y,表示 au=xa_u=xau​=x与 av=ya_v=y av​=y两者至少有一个成立。请判断是否至少存在一组 a 的值满足上述条件。

2-SAT是2-Satisfiability的意思,给一堆布尔变量,每个只有两种选择(1或0),要求满足方程组。

2-SAT的解题方法和差分约束一样是转化为图,然后对图进行操作。

要转化成图,可以把原式化成蕴含式(或者理解成如果...则一定...),给a、非a,b、非b分别建一个点,然后根据蕴含式的箭头连接边,这样就可以转换成图了。

这里的边(箭头)表示逻辑蕴含关系,因此同一个强连同分量内的变量值一定是同时成立的。也就是说,如果出现了如非a和a在同一个强连通分量里,那么就出现了矛盾,这个方程组是无解的。

这样就把方程组转化成了图论的找强连通分量的问题。

转换的方法:

原式
建图

然后用tarjan找强连通分量即可。

#include<cstdio>
#include<vector>
#include<stack>
using namespace std;
int n, m;
#define maxn 2000005
vector<int> vec[maxn];
int low[maxn], dfn[maxn],color[maxn], cnt = 0,cnt2 = 0;
bool vis[maxn];
stack<int> sta;

void tarjan(int u) {
	low[u] = dfn[u] = ++cnt;
	sta.push(u);
	vis[u] = true;
	for (int v : vec[u]) {
		if (!dfn[v]) {
			tarjan(v);
			low[u] = min(low[u], low[v]);
		}
		else if (vis[v]) {
			low[u] = min(low[u], dfn[v]);
		}
	}
	if (low[u] == dfn[u]) {
		cnt2++;
		while (sta.top() != u) {
			color[sta.top()] = cnt2;
			vis[sta.top()] = 0;
			sta.pop();
		}
		color[sta.top()] = cnt2;
		vis[sta.top()] = 0;
		sta.pop();
	}

}

int main() {
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= m; i++) {
		int u, x, v, y;
		scanf("%d %d %d %d", &u, &x, &v, &y);
		//建图
		if (!x && !y) {
			vec[u + n].push_back(v);
			vec[v + n].push_back(u);
		} else
		if (!x && y) {
			vec[v].push_back(u);
			vec[u + n].push_back(v+n);
		} else
		if (x && !y) {
			vec[v + n].push_back(u+n);
			vec[u].push_back(v);
		} else
		if (x && y) {
			vec[u].push_back(v + n);
			vec[v].push_back(u + n);
		}
	}

	for (int i = 1; i <= n * 2; i++) {
		if (!dfn[i]) tarjan(i);
	}

	for (int i = 1; i <= n; i++) {
		if (color[i] == color[i + n]) {
			printf("NO");
			return 0;
		}
	}

	printf("YES");

}
上一页DP的背包问题小结-java语言描述下一页【集训整理】Tarjan算法 模板题

最后更新于2年前

ega∨beg a\vee bega∨b
a→b∧¬b→¬aa\rightarrow b\wedge\neg b\rightarrow\neg aa→b∧¬b→¬a
a∨ba \vee ba∨b
ega→b∧¬b→aeg a\rightarrow b\wedge\neg b\rightarrow aega→b∧¬b→a
ega∨¬b  eg a\vee\neg b\space \spaceega∨¬b  
a→¬b∧b→¬aa\rightarrow\neg b\wedge b\rightarrow\neg aa→¬b∧b→¬a