【模板】2-SAT

题目大意:给定 N 个点的 M 条约束,约束形式为:\(a_i \lor a_j = 1\)

题解:拆点什么的就不说了,在求出一组解的时候,考虑到 Tarjan 找环的过程中,scc 染色是按照拓扑序的逆序来进行的,即:拓扑排序中最后被删除的节点的 cor 值最小。根据这个性质,在一定有解的情况下,对于任意一个 \(a_i\),应该取拓扑序大的值(Tarjan 染色小的值)作为最终结果,因为缩点之后的 DAG 上的边依然是选了前一个scc 就必然选与之相连的 scc。

代码如下

#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define all(x) x.begin(),x.end()
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int inf=0x3f3f3f3f;
const int maxn=2e6+10;

inline int read(){
	int x=0,f=1;char ch;
	do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
	do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
	return f*x;
}

int n,m;
vector<int> G[maxn];
int dfs_clk,dfn[maxn],low[maxn],stk[maxn],top,in[maxn];
int scc,cor[maxn];

void tarjan(int u){
	dfn[u]=low[u]=++dfs_clk;
	stk[++top]=u,in[u]=1;
	for(int i=0;i<G[u].size();i++){
		int v=G[u][i];
		if(!dfn[v])tarjan(v),low[u]=min(low[u],low[v]);
		else if(in[v])low[u]=min(dfn[v],low[u]);
	}
	if(dfn[u]==low[u]){
		++scc;int v;
		do{
			v=stk[top--],in[v]=0;
			cor[v]=scc;
		}while(u!=v);
	}
}

void read_and_parse(){
	n=read(),m=read();
	while(m--){
		int i=read(),a=read(),j=read(),b=read();
		if(a&&b)G[i].pb(j+n),G[j].pb(i+n);
		else if(a&&!b)G[i].pb(j),G[j+n].pb(i+n);
		else if(!a&&b)G[i+n].pb(j+n),G[j].pb(i);
		else G[i+n].pb(j),G[j+n].pb(i);
	}
}
void solve(){
	for(int i=1;i<=n<<1;i++)if(!dfn[i])tarjan(i);
	for(int i=1;i<=n;i++)if(cor[i]==cor[i+n])return (void)puts("IMPOSSIBLE");
	puts("POSSIBLE");
	for(int i=1;i<=n;i++)printf("%d ",!(cor[i]<cor[i+n]));
	puts("");
}
int main(){
	read_and_parse();
	solve();
	return 0;
}

posted @ 2019-03-28 20:00  shellpicker  阅读(144)  评论(0编辑  收藏  举报