傳送門
2-sat的板子
把每乙個點拆成選0或選1
條件為$x_i$為$a$或$x_j$為$b$,那麼如果$x_i$不為$a$則$x_j$必為$b$,同理$x_j$不為$b$則$x_i$必為$a$
那麼從$x_i$不為$a$的點向$x_j$為$b$的點連邊,從$x_j$不為$b$的點向$x_i$為$a$的點連邊
然後跑乙個tarjan縮點,在新的dag的反圖上跑一遍拓撲排序,如果有乙個點的兩個取值在同乙個強連通分量裡就無解,否則取兩個取值中拓撲序小的那乙個
有乙個小技巧就是tarjan縮點時的編號實際就是新的dag的反圖拓撲序,那麼只要看兩個取值誰的拓撲序更小取誰就行了
1//minamoto
2 #include3 #include4
using
namespace
std;
5#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?eof:*p1++)
6char buf[1
<<21],*p1=buf,*p2=buf;
7 templateinline bool cmin(t&a,const t&b)
8 inline int
read()
18char sr[1
<<21],z[20];int c=-1
,z;19 inline void ot()
20 inline void print(int
x)25
const
int n=2e6+5;26
inthead[n],next[n],ver[n],tot;
27 inline void add(int u,int
v)30
intdfn[n],bl[n],low[n],st[n],top,num,cnt,n,m;
31void tarjan(int
u)38
if(low[u]==dfn[u]) for(++cnt;st[top+1]!=u;--top) bl[st[top]]=cnt;39}
40int
main()
47for(int i=1,l=n<<1;i<=l;++i) if(!dfn[i]) tarjan(i);
48for(int i=1;i<=n;++i)
49if(bl[i]==bl[i+n]) return puts("
impossible
"),0
;50 puts("
possible");
51for(int i=1;i<=n;++i) print(bl[i+n]52ot();
53return0;
54 }
《P4782 模板 2 SAT 問題》
2 sat問題 就是一些元素,他們的值只能為布林值0,1.給出一些限制關係,並且每對關係都是兩個數之間的。讓你找出一組構造,讓所有關係都滿足。解法 首先要建圖 我們規定,a為1的點為a n,a為0的點為a。那麼對於給定的一對關係a b。如果是a 1,b 1,那麼說明a b。利用可以轉化為 a b,b...
題解 P4782 模板 2 SAT 問題
將每乙個點 x i 拆成 2i 和 2i 1 2i 表示 x i 的假狀態,2i 1 表示 x i 的真狀態 問題就化為了從2n個狀態中選出原來的每乙個 x i 的乙個狀態。這有什麼用呢?別急,先舉個栗子,1 1 3 0 就可以用有向邊 2 6 7 3 來表示,什麼意思呢?2表示1為false,根據...
題解 P4782 模板 2 SAT 問題
將每乙個點 x i 拆成 2i 和 2i 1 2i 表示 x i 的假狀態,2i 1 表示 x i 的真狀態 問題就化為了從2n個狀態中選出原來的每乙個 x i 的乙個狀態。這有什麼用呢?別急,先舉個栗子,1 1 3 0 就可以用有向邊 2 6 7 3 來表示,什麼意思呢?2表示1為false,根據...