http://blog.sina.com.cn/s/blog_64675f540100k2xj.html
http://www.cppblog.com/MatoNo1/archive/2011/07/13/150766.aspx
讲解看的这两篇博客,其实最好直接去看国家集训队的论文,别的抄来抄去想找个原始出处都难,不过我也没什么原则说这话就对了。。
求出强连通分量后进行缩点,新图是dag图,具有拓扑性质,直接在上面进行染色
http://acm.hdu.edu.cn/showproblem.php?pid=3062
2-sat判定性,复杂度O(M)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <queue> #include <map> using namespace std ; struct node { int s,t,nxt ; }e[4000005] ; int n,m,idx,ans,tp,cnt,dfn[100005],vis[100005],low[100005],head[100005],st[100005],belong[100005] ; void add(int s,int t) { e[cnt].s=s ; e[cnt].t=t ; e[cnt].nxt=head[s] ; head[s]=cnt++ ; } void tarjan(int u) { dfn[u]=low[u]=++idx ; vis[u]=1 ; st[++tp]=u ; int v ; for(int i=head[u] ;i!=-1 ;i=e[i].nxt) { v=e[i].t ; if(!dfn[v]) { tarjan(v) ; low[u]=min(low[u],low[v]) ; } else if(vis[v]) low[u]=min(low[u],dfn[v]) ; } if(dfn[u]==low[u]) { ans++ ; while(1) { v=st[tp--] ; vis[v]=0 ; belong[v]=ans ; if(v==u)break ; } } } bool _2sat() { memset(vis,0,sizeof(vis)) ; memset(dfn,0,sizeof(dfn)) ; idx=tp=ans=0 ; for(int i=0 ;i<2*n ;i++) if(!dfn[i]) tarjan(i) ; for(int i=0 ;i<n ;i++) if(belong[2*i]==belong[(2*i)^1]) return false ; return true ; } int main() { while(~scanf("%d%d",&n,&m)) { cnt=0 ; memset(head,-1,sizeof(head)) ; while(m--) { int a,b,c,d ; scanf("%d%d%d%d",&a,&b,&c,&d) ; int u,v ; u=a*2+c ;v=b*2+d ; add(u,v^1) ;add(v,u^1) ; } if(_2sat())puts("YES") ; else puts("NO") ; } return 0 ; }
http://acm.hit.edu.cn/hoj/problem/view?id=1917
2-sat判定性,且能输出任意一组解,解法见赵爽的集训队论文,复杂度O(M)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <queue> #include <map> using namespace std ; struct node { int s,t,nxt ; }e[400005],dag[400005] ; int n,m,idx,ans,tp,cnt,dfn[100005],vis[100005],low[100005],head[100005],st[100005],belong[100005] ; void add(int s,int t) { e[cnt].s=s ;e[cnt].t=t ;e[cnt].nxt=head[s] ;head[s]=cnt++ ; } int cntdag,headdag[100005] ; void adddag(int s,int t) { dag[cnt].s=s ;dag[cnt].t=t ;dag[cnt].nxt=head[s] ;headdag[s]=cntdag++ ; } void tarjan(int u) { dfn[u]=low[u]=++idx ; vis[u]=1 ; st[++tp]=u ; int v ; for(int i=head[u] ;i!=-1 ;i=e[i].nxt) { v=e[i].t ; if(!dfn[v]) { tarjan(v) ; low[u]=min(low[u],low[v]) ; } else if(vis[v]) low[u]=min(low[u],dfn[v]) ; } if(dfn[u]==low[u]) { ans++ ; while(1) { v=st[tp--] ; vis[v]=0 ; belong[v]=ans ; if(v==u)break ; } } } void builddag() { cntdag=0 ; memset(headdag,-1,sizeof(headdag)) ; for(int i=0 ;i<2*n ;i++) { for(int j=headdag[i] ;j!=-1 ;j=dag[j].nxt) { int v=e[j].t ; if(belong[v]!=belong[i])//缩点 adddag(belong[v],belong[i]) ;//建立反向边 } } } int color[100005],cp[100005] ; void bfs()//染色 { memset(color,0,sizeof(color)) ; queue <int> q ; for(int i=1 ;i<=ans ;i++) q.push(i) ; while(!q.empty()) { int u=q.front() ; q.pop() ; if(!color[u]) { color[u]=1 ; color[cp[u]]=-1 ; } for(int i=headdag[u] ;i!=-1 ;i=dag[i].nxt) { int v=dag[i].t ; q.push(v) ; } } } void _2sat() { memset(vis,0,sizeof(vis)) ; memset(dfn,0,sizeof(dfn)) ; idx=tp=ans=0 ; for(int i=0 ;i<2*n ;i++) if(!dfn[i]) tarjan(i) ; for(int i=0 ;i<n ;i++) { if(belong[2*i]==belong[(2*i)^1]) { puts("NIE") ; return ; } else { cp[belong[i*2]]=belong[(i*2)^1] ; cp[belong[(i*2)^1]]=belong[i*2] ; } } builddag() ; bfs() ; for(int i=0 ;i<2*n ;i+=2) { if(color[belong[i]]==1) printf("%d ",i+1) ; else printf("%d ",i+2) ; } return ; } int main() { while(~scanf("%d%d",&n,&m)) { cnt=0 ; memset(head,-1,sizeof(head)) ; while(m--) { int a,b ; scanf("%d%d",&a,&b) ; a-- ;b-- ; add(a,b^1) ;add(b,a^1) ; } _2sat() ; } return 0 ; }
http://acm.hdu.edu.cn/showproblem.php?pid=1814
2-sat判定且能输出字典序最小的一组解,复杂度O(NM)
不过这个做法我还没看,已经快吐了,先放到这里不管
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <stdio.h> using namespace std; #define re(i, n) for (int i=0; i<n; i++) const int MAXN = 20000, MAXM = 100000, INF = ~0U >> 2; struct node { int a, b, pre, next; } E[MAXM], E2[MAXM]; int _n, n, m, V[MAXN], ST[MAXN][2], Q[MAXN], Q2[MAXN], vst[MAXN]; bool res_ex; void init_d() { re(i, n) E[i].a = E[i].pre = E[i].next = E2[i].a = E2[i].pre = E2[i].next = i; m = n; } void add_edge(int a, int b) { E[m].a = a; E[m].b = b; E[m].pre = E[a].pre; E[m].next = a; E[a].pre = m; E[E[m].pre].next = m; E2[m].a = b; E2[m].b = a; E2[m].pre = E2[b].pre; E2[m].next = b; E2[b].pre = m; E2[E2[m].pre].next = m++; } void solve() { re(i, n) {V[i] = 0; vst[i] = 0;} res_ex = 1; int i, i1, i2, j, k, len, front, rear, front2, rear2; bool ff; re(_i, _n) { if (V[_i << 1] == 1 || V[(_i << 1) + 1] == 1) continue; i = _i << 1; len = 0; if (!V[i]) { ST[len][0] = i; ST[len++][1] = 1; if (!V[i ^ 1]) {ST[len][0] = i ^ 1; ST[len++][1] = 2;} Q[front = rear = 0] = i; vst[i] = i1 = n + i; Q2[front2 = rear2 = 0] = i ^ 1; vst[i ^ 1] = i2 = (n << 1) + i; ff = 1; for (; front<=rear; front++) { j = Q[front]; for (int p = E[j].next; p != j; p=E[p].next) { k = E[p].b; if (V[k] == 2 || vst[k] == i2 || V[k ^ 1] == 1 || vst[k ^ 1] == i1) {ff = 0; break;} if (vst[k] != i1) { Q[++rear] = k; vst[k] = i1; if (!V[k]) {ST[len][0] = k; ST[len++][1] = 1;} } if (vst[k ^ 1] != i2) { Q2[++rear2] = k ^ 1; vst[k ^ 1] = i2; if (!V[k]) {ST[len][0] = k ^ 1; ST[len++][1] = 2;} } } if (!ff) break; } if (ff) { for (; front2<=rear2; front2++) { j = Q2[front2]; for (int p = E2[j].next; p != j; p=E2[p].next) { k = E2[p].b; if (V[k] == 1 || vst[k] == i1) {ff = 0; break;} if (vst[k] != i2) { vst[k] = i2; Q2[++rear] = k; if (!V[k]) {ST[len][0] = k; ST[len++][1] = 2;} } } if (!ff) break; } if (ff) { re(j, len) V[ST[j][0]] = ST[j][1]; continue; } } } i = (_i << 1) + 1; len = 0; if (!V[i]) { ST[len][0] = i; ST[len++][1] = 1; if (!V[i ^ 1]) {ST[len][0] = i ^ 1; ST[len++][1] = 2;} Q[front = rear = 0] = i; vst[i] = i1 = n + i; Q2[front2 = rear2 = 0] = i ^ 1; vst[i ^ 1] = i2 = (n << 1) + i; ff = 1; for (; front<=rear; front++) { j = Q[front]; for (int p = E[j].next; p != j; p=E[p].next) { k = E[p].b; if (V[k] == 2 || vst[k] == i2 || V[k ^ 1] == 1 || vst[k ^ 1] == i1) {ff = 0; break;} if (vst[k] != i1) { Q[++rear] = k; vst[k] = i1; if (!V[k]) {ST[len][0] = k; ST[len++][1] = 1;} } if (vst[k ^ 1] != i2) { Q2[++rear2] = k ^ 1; vst[k ^ 1] = i2; if (!V[k]) {ST[len][0] = k ^ 1; ST[len++][1] = 2;} } } if (!ff) break; } if (ff) { for (; front2<=rear2; front2++) { j = Q2[front2]; for (int p = E2[j].next; p != j; p=E2[p].next) { k = E2[p].b; if (V[k] == 1 || vst[k] == i1) {ff = 0; break;} if (vst[k] != i2) { vst[k] = i2; Q2[++rear] = k; if (!V[k]) {ST[len][0] = k; ST[len++][1] = 2;} } } if (!ff) break; } if (ff) { re(j, len) V[ST[j][0]] = ST[j][1]; continue; } } } if (V[_i << 1] + V[(_i << 1) + 1] != 3) {res_ex = 0; break;} } } int main() { int _m, a, b; while (scanf("%d%d", &_n, &_m) != EOF) { n = _n << 1; init_d(); re(i, _m) { scanf("%d%d", &a, &b); a--; b--; if (a != (b ^ 1)) {add_edge(a, b ^ 1); add_edge(b, a ^ 1);} } solve(); if (res_ex) {re(i, n) if (V[i] == 1) printf("%d ", i + 1);} else puts("NIE"); } return 0; }