1. 程式人生 > >學習筆記第二十八節:2-SAT

學習筆記第二十八節:2-SAT

正題

      我又來划水了。

      2-SAT問題是類似於這樣的形式:

      給出n個數\in 0\ or \ 1,m組條件,問你這m組條件是否能同時滿足。

      每組條件類似於這樣的形式(x=a\ |\ y=b)[a,b\in 0\ or\ 1]

      怎麼做?

       我們可以拆點!

       把每個點拆成兩個點,一個表示選,一個表示不選。

       那麼假如有一個這樣一個條件:x=0\ |\ y=0

       考慮x取1時,y必須取0;y取1時,x必須取0.

       所以我們建兩條邊:(x_1,y_0),(y_1,x_0)

       表示的就是上面的意思。

       接下來,讓我們透徹理解邊的意思。

       邊的意思就是,如果a滿足,b必須滿足。

       顯然x_0,x_1不可能同時取。

       在圖中怎麼表示呢?!!原來是強聯通分量

!首先,強聯通分量的要麼同時取要麼同時不取。

       所以如果x_0,x_1在同一強聯通分量,那麼很明顯是矛盾的。如果有,輸出Impossible。

       否則就肯定存在一組解。a\to b有路徑,那麼a取,b必須取。

       對於x_0,x_1如果在一個聯通分量,那麼肯定取拓撲序大的,為什麼?因為如果取拓撲序小的,那麼拓撲序大的那個可能也會取到,就會矛盾,為了避免意外,我們選擇拓撲序大的。

       如果不在一個連通分量,那麼我們取那個都無所謂。

       所以,取拓撲序大的就可以了。(當然這裡的拓撲序是縮點後的拓撲序

       最後,因為Tarjan是深搜,搜出來的拓撲序一定是倒序的,所以寫的時候選小的。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<stack>
using namespace std;

int n,m;
struct edge{
	int y,next;
}s[2000010];
int first[2000010],len=0;
int t=0,T=0;
int dfn[2000010],low[2000010],tim[2000010];
bool tf[2000010];
stack<int> f;

void ins(int x,int y){
	len++;
	s[len]=(edge){y,first[x]};first[x]=len;
}

void Tarjan(int x){
	dfn[x]=low[x]=++t;
	f.push(x);tf[x]=true;
	for(int i=first[x];i!=0;i=s[i].next){
		int y=s[i].y;
		if(!dfn[y]){
			Tarjan(y);
			low[x]=min(low[y],low[x]);
		}
		else if(tf[y]) low[x]=min(low[x],dfn[y]);
	}
	if(dfn[x]==low[x]){
		T++;
		int d;
		tim[x]=T;
		tf[x]=false;
		while((d=f.top())!=x){
			f.pop();
			tim[d]=T;
			tf[d]=false;
		}
		f.pop();
	}
}

int main(){
	scanf("%d %d",&n,&m);
	int x,a,y,b;
	for(int i=1;i<=m;i++){
		scanf("%d %d %d %d",&x,&a,&y,&b);
		if(a==0 && b==0) ins(x,y+n),ins(y,x+n);
		if(a==0 && b==1) ins(x,y),ins(y+n,x+n);
		if(a==1 && b==0) ins(x+n,y+n),ins(y,x);
		if(a==1 && b==1) ins(x+n,y),ins(y+n,x);
	}
	for(int i=1;i<=2*n;i++)	
		if(!dfn[i]) Tarjan(i);
	for(int i=1;i<=n;i++)
		if(tim[i]==tim[i+n]){
			printf("IMPOSSIBLE");
			return 0;
		}
	printf("POSSIBLE\n");
	for(int i=1;i<=n;i++)
		printf("%d ",tim[i]<tim[i+n]);
	printf("\n");
}