2-SAT( tarjan应用 )
大佬博客:here
模板题目:P4782 【模板】2-SAT 问题
AC_Code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef long double ld; 5 #define endl '\n' 6 const int inf=0x3f3f3f3f; 7 const int maxn=2e6+10; 8 const int maxm=4e6+10; 9 10 struct node{ 11 int to,nxt; 12 }e[maxm]; 13 14 int head[maxn],tot; 15 int dfn[maxn],low[maxn],cnt; //dfn[i]:i被访问的时间点,low[i]:通过有向边可回溯到的最早的时间点 cnt为时间戳 16 int _stack[maxn],top; 17 bool instack[maxn]; 18 int belong[maxn],scnt; //belong[i]:i所属的强联通分量的编号,scnt:记录强联通分量的个数,以及每一个强联通分量的个数 19 int n,m; 20 21 void init(){ 22 memset(head,-1,sizeof(head)); tot=0; 23 memset(instack,false,sizeof(instack)); top=0; 24 memset(dfn,0,sizeof(dfn)); cnt=0; 25 scnt=0; 26 } 27 28 void addedge(int u,int v){ 29 e[tot].to=v; e[tot].nxt=head[u]; head[u]=tot++; 30 } 31 32 void tarjan_dfs(int u){ 33 dfn[u] = low[u] = ++cnt; 34 instack[u]=true; //标记u已经在栈中 35 _stack[top++]=u; //u入栈 36 for(int i=head[u];~i;i=e[i].nxt){ 37 int to=e[i].to; 38 if( !dfn[to] ){ //未被访问,继续向下dfs 39 tarjan_dfs(to); 40 if( low[u]>low[to] ) low[u]=low[to]; //更新节点u所能到达的最小时间 41 } 42 else if( instack[to] && low[u]>dfn[to]){ //如果to已经在栈中 43 low[u]=dfn[to]; 44 } 45 } 46 if( low[u]==dfn[u] ){ //如果节点u是强连通分量的根 47 scnt++; //连通分量个数加1 48 while(1){ 49 int v=_stack[--top]; //退栈 50 // printf("%d-",v); //输出 51 instack[v]=false; //标记不在栈中 52 belong[v]=scnt; 53 if( v==u ) break; 54 } 55 // printf("\n"); 56 } 57 } 58 59 int main() 60 { 61 init(); 62 scanf("%d%d",&n,&m); 63 for(int i=1; i<=m; i++){ 64 int a,b,x,y; cin>>a>>x; cin>>b>>y; 65 if( x && y ){ // a∨b : ¬a→b ∧ ¬b→a 66 addedge(a+n,b); 67 addedge(b+n,a); 68 } 69 else if( !x && y ){ // ¬a∨b : a→b ∧ ¬b→¬a 70 addedge(a,b); 71 addedge(b+n,a+n); 72 } 73 else if(x&&!y){ // ¬b∨a : b→a ∧ ¬a→¬b 74 addedge(b,a); 75 addedge(a+n,b+n); 76 } 77 else if(!x&&!y){ // ¬a∨¬b : a→¬b ∧ b→¬a 78 addedge(a,b+n); 79 addedge(b,a+n); 80 } 81 } 82 83 for(int i=1;i<=2*n;i++){ 84 if( !dfn[i] ){ 85 tarjan_dfs(i); 86 } 87 } 88 89 for(int i=1;i<=n;i++){ 90 if( belong[i]==belong[i+n] ){ 91 printf("IMPOSSIBLE\n"); 92 return 0; 93 } 94 } 95 96 printf("POSSIBLE\n"); 97 for(int i=1;i<=n;i++){ 98 if( belong[i]<belong[i+n] ){ 99 if( i==1 ) printf("1"); 100 else printf(" 1"); 101 } 102 else{ 103 if( i==1 ) printf("0"); 104 else printf(" 0"); 105 } 106 } 107 printf("\n"); 108 return 0; 109 }