2-SAT 模板

2-SAT 问题:

有 n 个变量,每一个变量都是 bool 类型的,除了这 n 个变量以外,我们还有 m 个关系表达式,关系表达式差不多是这样的:

x 1 & x 2 = f a l s e x1 \& x2 = false x1&x2=false(注意每个表达式只会有两个变量)

问给出 m 个关系表达式后,能否给这 n 个变量找出一个赋值的方法,使得满足所有的表达式;

>face<

前置技能:tarjan求最大连通分量

#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
#define _rep(n, a, b) for (ll n = (a); n <= (b); ++n)
#define _rev(n, a, b) for (ll n = (a); n >= (b); --n)
#define _for(n, a, b) for (ll n = (a); n < (b); ++n)
#define _rof(n, a, b) for (ll n = (a); n > (b); --n)
#define oo 0x3f3f3f3f3f3f
#define ll long long
#define db double
#define eps 1e-8
#define bin(x) cout << bitset<10>(x) << endl;
#define what_is(x) cerr << #x << " is " << x << endl
#define met(a, b) memset(a, b, sizeof(a))
#define all(x) x.begin(), x.end()
#define pii pair<ll, ll>
const ll mod = 1e9 + 7;
const ll maxn = 2e6 + 5;
struct node
{
	int nxt, to;
} way[maxn];
int cnt, head[maxn], dfn[maxn], tim, low[maxn], vis[maxn], st[maxn], top, scc_sum, scc[maxn];
void addedge(int from, int to)
{
	way[++cnt].to = to;
	way[cnt].nxt = head[from];
	head[from] = cnt;
}
int n, m;
void tarjan(int cur, int fa)
{ //求强连通分量
	dfn[cur] = low[cur] = ++tim;
	st[++top] = cur;
	vis[cur] = 1;
	for (int i = head[cur]; i; i = way[i].nxt)
	{
		int to = way[i].to;
		if (to == fa)
			continue;
		if (!dfn[to])
		{
			tarjan(to, cur);
			low[cur] = min(low[cur], low[to]);
		}
		else if (vis[to])
			low[cur] = min(low[cur], dfn[to]);
	}
	if (dfn[cur] == low[cur])
	{
		scc_sum++;
		while (st[top] != cur)
		{
			scc[st[top]] = scc_sum;
			vis[st[top--]] = 0;
		}
		scc[st[top]] = scc_sum;
		vis[st[top--]] = 0;
	}
}
signed main()
{
	
	cin >> n >> m;
	_rep(i, 1, m)
	{
		int a, val_a, b, val_b;
		cin >> a >> val_a >> b >> val_b;
		addedge(b + (1 ^ val_b) * n, a + val_a * n);
		addedge(a + (val_a ^ 1) * n, b + val_b * n);
	}
	_rep(i, 1, 2 * n)
	{
		if (!dfn[i])
			tarjan(i, 0);
	}
	_rep(i, 1, n)
	{
		if (scc[i] == scc[i + n])
		{ //两种取值在同一连通分量中
			return puts("IMPOSSIBLE"), 0;
		}
	}
	puts("POSSIBLE");
	_rep(i, 1, n)
	{
		if (scc[i] > scc[i + n])
			cout << 1 << " "; //强连通分量编号越小, top序越大, 就越优
		else
			cout << 0 << " ";
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值