2-SAT-学习笔记

基本知识复习

https://oi-wiki.org/graph/2-sat/

模板

【模板】2-SAT 问题

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e6+5;
int n,m;
int cvrt(int u, int tp) { return tp?u:u+n; }
vector<int> g[N];
int dfn[N],low[N],col[N],st[N],tp,in_st[N],ct,ncol;
void tarjan(int u)
{
	dfn[u]=low[u]=++ct;
	st[++tp]=u; in_st[u]=1;
	for(int v:g[u])
		if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
	    else if(in_st[v]) low[u]=min(low[u],dfn[v]); // 这第二个一定是 dfn[v]
    if(dfn[u]==low[u])
    {
    	ncol++; int v;
    	do { v=st[tp--],in_st[v]=0,col[v]=ncol; } while(u!=v); // 这边我写法很容易搞错 tcl
    }
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1,ti,ta,tj,tb; i<=m; i++)
	{
		scanf("%d%d%d%d",&ti,&ta,&tj,&tb);
		if(ti==tj and ta!=tb) continue;
		g[cvrt(ti,!ta)].push_back(cvrt(tj,tb)); // !i->j
		if(ti==tj and ta==tb) continue;
		g[cvrt(tj,!tb)].push_back(cvrt(ti,ta)); // !j->i
	}
	for(int i=1; i<=(n<<1); i++) if(!dfn[i]) ct=0,tarjan(i);
	for(int i=1; i<=n; i++) if(col[i]==col[i+n]) { puts("IMPOSSIBLE"); return 0; } //如果 !u->u and u->!u 肯定是假的
	puts("POSSIBLE");
	for(int i=1; i<=n; i++) printf("%d ",(col[i]<col[i+n])); //肯定选拓扑序靠后的,也就是 col 小的 注意 tarjan 是反的拓扑序
	return 0;
}

例题

1

posted @ 2023-02-08 23:41  copper_carbonate  阅读(12)  评论(0编辑  收藏  举报