首页 > 其他分享 >2-SAT

2-SAT

时间:2023-01-30 09:46:37浏览次数:29  
标签:vis int tot ++ low SAT

Before \(2-SAT\)

一般形式为 \(k-适定性问题\),简称 \(k-SAT\)
\(k>2\)为\(NP\)完全,暂不考虑,现考虑\(2-SAT\)

模型

有若干个包含2个元素的集合,只能选择每个集合中的一个元素,并给出一些条件(例:选a后不能选b),要求求出满足这些条件的选择,这个解也称为\(2-SAT\)的解

A  B  C
A' B' C'

若给出条件,{A,B'} , {B'C'} 不能同时选择
因为 {A,A'} , {B,B'} , {C,C'} 中,每个集合都要选出一个元素,即不能同时选择
又因为 {A,B'} 不能同时选择,则选择B'时,一定选择A',于是在 B',A' 之间连上一条有向边(因选 A' 不一定 B');同理,在选 B 时也一定选 A

于是可以建图

集合内元素是否矛盾就是\(Tarjan\)缩点之后,矛盾的元素是否在一个\(SCC\)
有,则不存在解
输出方案时可以通过变量在图中的拓扑序确定该变量的取值
我们可以发现,缩点后强连通分量的编号就是反着的拓扑排序
时间复杂度\(O(n+m)\)

非常的板,精髓在灵活建图

int head[N],nxt[N],to[N],tot=0;
int dfn[N],low[N],cnt=0;
int st[N],vis[N],pot[N],d[N],p[N],tp;
int n,m,t=0;

void add(int u,int v) {
	
	nxt[++tot]=head[u];
	to[tot]=v;
	head[u]=tot;
	
}

void Tarjan(int u) {
	
	low[u]=dfn[u]=++t;
	st[++tp]=u;
	vis[u]=1;
	
	for(int i=head[u];i;i=nxt[i]) {
		
		int v=to[i];
		if(!dfn[v]) {
			Tarjan(v);
			low[u]=min(low[u],low[v]);
		} else if(vis[v]) {
			low[u]=min(low[u],low[v]);
		}
		
	}
	if(dfn[u]==low[u]) {
		
		int v;
		cnt++;
		while(v=st[tp--]) {
			
			pot[v]=u;
			vis[v]=0;
			d[v]=cnt;
			if(u==v) break;
			
		}
		
	}
	
}
bool fl=1;

signed main() {
	
	n=read();
	m=read();
	
	for(int i=1;i<=m;i++) {
		
		int u=read(),iu=read(),v=read(),iv=read();
		add(u+(iu^1)*n,v+iv*n);//建图,以题意为准灵活更改
		add(v+(iv^1)*n,u+iu*n);
		
	}
	
	for(int i=1;i<=n*2;i++) {
		if(!dfn[i]) Tarjan(i);
	}
	//...
	
	return 0;
}

标签:vis,int,tot,++,low,SAT
From: https://www.cnblogs.com/Diamondan/p/17074415.html

相关文章