1. 程式人生 > 實用技巧 >2-SAT( tarjan應用 )

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 }