• 【模板】2-SAT


    【模板】2-SAT 问题

    题目描述

    n n n 个布尔变量 x 1 x_1 x1 ∼ \sim x n x_n xn,另有 m m m 个需要满足的条件,每个条件的形式都是 「 x i x_i xitrue / false x j x_j xjtrue / false」。比如 「 x 1 x_1 x1 为真或 x 3 x_3 x3 为假」、「 x 7 x_7 x7 为假或 x 2 x_2 x2 为假」。

    2-SAT 问题的目标是给每个变量赋值使得所有条件得到满足。

    输入格式

    第一行两个整数 n n n m m m,意义如题面所述。

    接下来 m m m 行每行 4 4 4 个整数 i i i, a a a, j j j, b b b,表示 「 x i x_i xi a a a x j x_j xj b b b」( a , b ∈ { 0 , 1 } a, b\in \{0,1\} a,b{0,1})

    输出格式

    如无解,输出 IMPOSSIBLE;否则输出 POSSIBLE

    下一行 n n n 个整数 x 1 ∼ x n x_1\sim x_n x1xn x i ∈ { 0 , 1 } x_i\in\{0,1\} xi{0,1}),表示构造出的解。

    样例 #1

    样例输入 #1

    3 1
    1 1 3 0
    
    • 1
    • 2

    样例输出 #1

    POSSIBLE
    0 0 0
    
    • 1
    • 2

    提示

    1 ≤ n , m ≤ 1 0 6 1\leq n, m\leq 10^6 1n,m106 , 前 3 3 3 个点卡小错误,后面 5 5 5 个点卡效率。

    由于数据随机生成,可能会含有( 10 0 10 0)之类的坑,但按照最常规写法的写的标程没有出错,各个数据点卡什么的提示在标程里。

    思路

    对于一个 a   o r   b a\ or\ b a or b的表达式,我们可以拆成 ( ! a   a n d   b )   o r   ( ! b   a n d   a )   o r   ( a   a n d   b ) (!a\ and\ b)\ or\ (!b\ and\ a)\ or\ (a\ and\ b) (!a and b) or (!b and a) or (a and b)
    我们可以建图 ! a → b !a→ b !ab ! b → a !b→a !ba表示选了 ! a !a !a就得选 b b b,反之亦然。

    习惯上,我们给缩点后的图排一个拓扑序,当 x x x 所在强连通分量的拓扑序在 ! x !x !x 所在的强连通分量的拓扑序之后的话我们就给 x x x 取真。

    这题tarjan缩完点就已经有个顺序了,不过这是反着的拓扑序,所以比较关系是反着的。

    #include
    #define int long long
    using namespace std;
    const int N=2e6+77;
    int dfn[N],low[N],b[N],s[N],c[N],ls[N],cnt,id,top,tot;
    struct E
    {
    	int to,next;
    }e[N<<1];
    void add(int u,int v)
    {
    	e[++cnt].to=v; e[cnt].next=ls[u]; ls[u]=cnt;
    }
    void tarjan(int u)
    {
    	dfn[u]=low[u]=++tot; b[u]=1;
    	s[++top]=u; 
    	for(int i=ls[u]; i; i=e[i].next)
    	{
    		int v=e[i].to;
    		if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
    		else if(b[v]) low[u]=min(low[u],dfn[v]);
    	}
    	if(low[u]==dfn[u])
    	{
    		id++;
    		while(s[top+1]!=u)
    		{
    			c[s[top]]=id;
    			b[s[top]]=0; top--;
    		}
    	}
    }
    void solve()
    {
    	int n,m;
    	cin>>n>>m;
    	for(int i=1; i<=m; i++)
    	{
    		int x,y,a,b;
    		cin>>x>>a>>y>>b;
    		x<<=1; y<<=1;
    		x^=a; y^=b;
    		add(x^1,y); add(y^1,x);
    	}
    	for(int i=2; i<=2*n+1; i++) if(!dfn[i]) tarjan(i);
    	for(int i=1; i<=n; i++)
    	{
    		if(c[i*2]==c[(i*2)^1])
    		{
    			cout<<"IMPOSSIBLE"; return;
    		}
    	}
    	cout<<"POSSIBLE\n";
    	for(int i=1; i<=n; i++)
    	{
    		if(c[i<<1]<c[(i<<1)^1]) cout<<"0 ";else cout<<"1 ";
    	}
    }
    signed main()
    {
    	ios::sync_with_stdio(false); cin.tie(0),cout.tie(0);
    	
    	int T=1;
    //	cin>>T;
    	while(T--)
    	{
    		solve();
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
  • 相关阅读:
    k8s实战案例之运行WordPress
    深入学习JVM底层(三):垃圾回收器与内存分配策略
    MySQL常用指令
    vue实现关键字查询列表数据
    hadoopHa集群namenode起不来的原因(1)
    偶数科技发布 OushuDB 5.0,多活主节点、多虚拟集群等特性完美支持实时湖仓一体
    e-table,表格单元格合并
    41.cuBLAS开发指南中文版--cuBLAS中的Level-2方法gemvStridedBatched()
    linux下基于boost/process库实现多进程管理,基于c++开发
    Oracle进阶
  • 原文地址:https://blog.csdn.net/Eric1561759334/article/details/133255581