2-SAT學習筆記
阿新 • • 發佈:2021-11-09
演算法&模板
演算法
應用的問題
當有一堆的非黑即白的關係,且關係兩兩間存在一定的限制
此時可以運用2-SAT演算法來求出可行解或者判斷無解
引入
存在n個點,要求對點進行黑白染色,有m條限制形如:\((u,f_1,v,f_2)\)
表示 [ \(u\) 號點為 \(f_1\) 或 \(v\) 號點為 \(f_2\) ] ,求一組可行解
考慮將"或" 這種比較模糊的條件限制給固定住
即: 對於\((u,f_1,v,f_2)\)
有:
- \(u\) 號點不為 \(f_1\)時, \(v\) 號點為 \(f_2\)
- \(v\) 號點不為 \(f_2\)時, \(u\) 號點為 \(f_1\)
那麼我們可以從u和v的部分取值中確切的推出對方的取值了
但此處是部分取值,那麼考慮拆點,將每個點 \(u\) 拆成兩個點,分別代表 \(u\) 選白和 \(u\)選黑
然後按照上面列出的限制,將每個點的狀態向可推出的其他點的相應狀態連邊即可
連邊後發現若發現點u的黑點與白點同處一個環內,則代表限制存在矛盾
否則,對於每個原先的點將它的縮點拓撲序較大的新點作為答案
code
建圖
for(int i=1;i<=n;++i) id[0][i]=i+n, id[1][i]=i; for(int i=1;i<=m;++i) { int u=read(), x=read(), v=read(), y=read(); add(id[1^x][u],id[y][v]); add(id[1^y][v],id[x][u]); }
tarjan縮點
int col[_<<1], st[_<<1], top, dfn[_<<1], low[_<<1], cnt, num, id[2][_]; void tarjan(int u) { low[u]=dfn[u]=++cnt, st[++top]=u; for(int i=h[u];i;i=e[i].ne) { int v=e[i].to; if(dfn[v] && !col[v]) low[u]=min(low[u], dfn[v]); else if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]);} } if(dfn[u]!=low[u]) return; col[u]=++num; while(st[top]!=u) col[st[top]]=num, top--; top--; }
check&getans
for(re int i=1;i<=n;++i) if(col[i]==col[n+i]) {puts("IMPOSSIBLE"); return 0;}
puts("POSSIBLE");
for(re int i=1;i<=n;++i) printf("%d ", (col[i]<col[i+n]));
例題
此坑待填