2-SAT

Before 2SAT

一般形式为 k,简称 kSAT
k>2NP完全,暂不考虑,现考虑2SAT

模型

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

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);
	}
	//...与d数组相关...
	
	return 0;
}

满汉全席
https://www.luogu.com.cn/problem/P4171

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N=8e3+100;

int read() {

	int x=0,f=1;
	char ch=getchar();
	while(ch<48||ch>57) {
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>=48&&ch<=57) {
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return x*f;

}

int head[N],nxt[N],to[N],tot=0;
int dfn[N],low[N],cnt=0;
int st[N],vis[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--]) {

			vis[v]=0;
			d[v]=cnt;
			if(u==v) break;

		}

	}

}
bool fl=1;

void init() {

	tp=0;
	cnt=0;
	tot=0;
	fl=1;
	memset(head,0,sizeof(head));
	memset(vis,0,sizeof(vis));
	memset(d,0,sizeof(d));
	memset(dfn,0,sizeof(dfn));
	memset(low,0,sizeof(low));

}

int get_num(string s) {
	
	int tt=1,o=0,len=s.length();
	while(s[tt]>=48&&s[tt]<=57&&tt<len) o=o*10+s[tt]-48,tt++;
	return o; 
	
}

int T;
string s1,s2;

signed main() {

	T=read();
	while(T--) {
		
		n=read();
		m=read();
		init(); 
		for(int i=1; i<=m; i++) {

			cin>>s1>>s2;
			int u=get_num(s1);
			int v=get_num(s2);
			if(s1[0]=='m') {
				if(s2[0]=='m') add(u+n,v),add(v+n,u);
				if(s2[0]=='h') add(u+n,v+n),add(v,u);
			} 
			if(s1[0]=='h') {
				if(s2[0]=='m') add(u,v),add(v+n,u+n);
				if(s2[0]=='h') add(u,v+n),add(v,u+n);
			}

		}

		for(int i=1; i<=n*2; i++) {
			if(!dfn[i]) Tarjan(i);
		}
		
		for(int i=1;i<=n;i++) {
			if(d[i]==d[i+n]) {
				fl=0;
				break;
			}
		}
		
		if(!fl) printf("BAD\n");
		else printf("GOOD\n");
		
	}
	return 0;
}

[POI2001] 和平委员会
https://www.luogu.com.cn/problem/P5782

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N=3e6+10;
const int inf=1e9;

int read() {

	int x=0,f=1;
	char ch=getchar();
	while(ch<48||ch>57) {
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>=48&&ch<=57) {
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return x*f;

}

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;
	
}

int partner(int x) {
	
	if(x&1) return x+1;
	else return x-1;
	
}

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(),v=read();
		add(u,partner(v));
		add(v,partner(u));
		
	}
	
	for(int i=1;i<=n*2;i++) {
		if(!dfn[i]) Tarjan(i);
	}
	
	for(int i=1;i<=n*2;i++) {
		if(d[i]==d[partner(i)]) fl=0;
	}
	
	if(!fl) printf("NIE\n");
	else {
		
		for(int i=1;i<=n*2;i++) {
			if(d[i]<d[partner(i)]) printf("%lld\n",i); 
		}
		
	}
	
	return 0;
}
posted @   Diamondan  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示