西安多校集训-2-SAT

2-SAT问题

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

$x_1 \text{&} x_2 = false $(注意每个表达式只会有两个变量)

问给出 m 个关系表达式后,能否给这 n 个变量找出一个赋值的方法,使得满足所有的表达式。
——来自洛谷题解区大佬

具体做法

有点像种类并查集?
如果我们令变量 \(i\) 表示 \(i\) 的状态 1 ,令\(i+n\) 表示 \(i\) 的状态 2 (只能有两种状态,且不能共存)。
那么如果此时有一变量 \(j\) 不能与 \(i\) 共存,那么令 \(j\)\(i+n\) 连边,同时 \(j+n\)\(i\) 连边。反之亦然。
然后直接 Tarjan 缩点,再根据题意做即可。

例题

【模板】2-SAT

如上述直接做即可。

#include<bits/stdc++.h>

using namespace std;
const int N=1e6+10;
int n,m;
vector<int> vec[2*N];
int dfn[2*N],low[2*N],dfx;
int sta[2*N],t;
bool vis[2*N];
int scc=0,color[2*N];
void tarjan(int u){
	dfn[u]=low[u]=++dfx;
	sta[++t]=u;
	vis[u]=1;
	for(auto 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]){
		scc++;
		while(sta[t]!=u){
			color[sta[t]]=scc;
			vis[sta[t]]=0;
			t--;
		}
		vis[u]=0;
		color[u]=scc;
		t--;
	}
	return ;
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int x,a,y,b;
		cin>>x>>a>>y>>b;
		vec[x+n*(a&1)].push_back(y+n*(b^1));
		vec[y+n*(b&1)].push_back(x+n*(a^1));
	}
	for(int i=1;i<=2*n;i++){
		if(!dfn[i]) tarjan(i);
	}
	for(int i=1;i<=n;i++){
		if(color[i]==color[i+n]){
			cout<<"IMPOSSIBLE";
			return 0;
		}
	}
	cout<<"POSSIBLE\n";
	for(int i=1;i<=n;i++){
		if(color[i]<color[i+n]) cout<<"1 ";
		else cout<<"0 ";
	}
	return 0;
}

因为 Tarjan 缩点得到的拓扑序是反的,所以最后输出时是小于号,如果你用别的,就是大于号。

和平委员会

怎么感觉比板子还简单呢。

#include<bits/stdc++.h>

using namespace std;
const int N=2e5+10;
int n,m;
vector<int> vec[4*N];
int get(int x){
	if(x%2==0) return x-1;
	else return x+1;
}
int dfn[N],low[N],dfx,sta[N],top;
int scc,color[N];
bool vis[N];
void tarjan(int u){
	dfn[u]=low[u]=++dfx;
	sta[++top]=u;
	vis[u]=1;
	for(auto 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]){
		scc++;
		while(sta[top]!=u){
			vis[sta[top]]=0;
			color[sta[top]]=scc;
			top--;
		}
		vis[u]=0;
		color[u]=scc;
		top--;
	}
	return ;
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		vec[u].push_back(get(v));
		vec[v].push_back(get(u));
	}
	for(int i=1;i<=2*n;i++){
		if(!dfn[i]) tarjan(i);
	}
	for(int i=1;i<=2*n;i+=2){
		if(color[i]==color[i+1]){
			cout<<"NIE";
			return 0;
		}
	}
	for(int i=1;i<=2*n;i+=2){
		if(color[i]<color[i+1]){
			cout<<i<<'\n';
		}else{
			cout<<i+1<<'\n';
		}
	}
	return 0;
}
posted @ 2025-04-01 16:17  Tighnari  阅读(21)  评论(0)    收藏  举报