• 【刷题】洛谷 P4782 【模板】2-SAT 问题


    题目背景

    2-SAT 问题 模板

    题目描述

    有n个布尔变量 (x_1)​~(x_n)​,另有m个需要满足的条件,每个条件的形式都是“(x_i)​为true/false或(x_j)​为true/false”。比如“(x_1)​为真或(x_3)​为假”、“(x_7)​为假或(x_2)​为假”。2-SAT 问题的目标是给每个变量赋值使得所有条件得到满足。

    输入输出格式

    输入格式:

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

    接下来m行每行4个整数 i a j b,表示“(x_i)​为a或(x_j)​为b”(a,b∈{0,1})

    输出格式:

    如无解,输出“IMPOSSIBLE”(不带引号); 否则输出"POSSIBLE"(不带引号),下 一行n个整数x_1x1​~x_nxn​(x_ixi​∈{0,1}),表示构造出的解。

    输入输出样例

    输入样例#1:

    3 1
    1 1 3 0
    

    输出样例#1:

    POSSIBLE
    0 0 0
    

    说明

    1<=n,m<=1e6 , 前3个点卡小错误,后面5个点卡效率,由于数据随机生成,可能会含有( 10 0 10 0)之类的坑,但按照最常规写法的写的标程没有出错,各个数据点卡什么的提示在标程里。

    题解

    2-SAT裸题

    2-SAT对于限制的处理非常的极简的,首先对每个点建两个点,表示两个状态,如果有某条限制为 “ (A_0)(B_1) 必须存在一个 ” ,那么就从 (A_1)(B_1) 连边,代表如果选了 (A_1) ,那么为了满足这个限制,就必须选 (B_1) ,而不能选 (B_0) ,然后还要将逆命题的边也连上

    反正就是按照正常思路来推导,2-SAT就是把一堆推导的思路建成边吗,然后跑tarjan缩点,如果某个点的两个状态在同一个强连通分量里,那显然就无解了,因为这个点无论选什么状态都会产生矛盾

    #include<bits/stdc++.h>
    #define ui unsigned int
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    const int MAXN=2000000+10;
    int n,m,e,beg[MAXN],nex[MAXN],to[MAXN],DFN[MAXN],LOW[MAXN],Visit_Num,Stack[MAXN],In_Stack[MAXN],Stack_Num,Be[MAXN],cnt;
    template<typename T> inline void read(T &x)
    {
    	T data=0,w=1;
    	char ch=0;
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    	x=data*w;
    }
    template<typename T> inline void write(T x,char ch='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(ch!='')putchar(ch);
    }
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    inline void insert(int x,int y)
    {
    	to[++e]=y;
    	nex[e]=beg[x];
    	beg[x]=e;
    }
    inline void Tarjan(int x)
    {
    	DFN[x]=LOW[x]=++Visit_Num;
    	In_Stack[x]=1;
    	Stack[++Stack_Num]=x;
    	for(register int i=beg[x];i;i=nex[i])
    		if(!DFN[to[i]])Tarjan(to[i]),chkmin(LOW[x],LOW[to[i]]);
    		else if(In_Stack[to[i]]&&DFN[to[i]]<LOW[x])LOW[x]=DFN[to[i]];
    	if(DFN[x]==LOW[x])
    	{
    		int temp;++cnt;
    		do{
    			temp=Stack[Stack_Num--];
    			In_Stack[temp]=0;
    			Be[temp]=cnt;
    		}while(temp!=x);
    	}
    }
    int main()
    {
    	read(n);read(m);
    	for(register int t=1;t<=m;++t)
    	{
    		int i,a,j,b;read(i);read(a);read(j);read(b);
    		insert(i<<1|a^1,j<<1|b);insert(j<<1|b^1,i<<1|a);
    	}
    	for(register int i=2;i<=(n<<1|1);++i)
    		if(!DFN[i])Tarjan(i);
    	for(register int i=2;i<=(n<<1|1);i+=2)
    		if(Be[i]==Be[i^1])
    		{
    			puts("IMPOSSIBLE");
    			return 0;
    		}
    	puts("POSSIBLE");
    	for(register int i=1;i<=n;++i)printf("%d ",Be[i<<1]<Be[i<<1|1]?0:1);
    	puts("");
    	return 0;
    }
    
  • 相关阅读:
    Datastage 调度相关 dsjob
    DropdownList内容树状展示 字段前空格不显示
    IE兼容低版本设置
    跑数速度慢,修改参数
    cognos samples 安装配置【转】
    在子窗口中操作父窗口(刷新)
    html长文本自动换行
    Asp.net禁止缓存
    【Range Lookup】 根据年龄 求年龄分段ID
    目标表已有对应数据则不插入
  • 原文地址:https://www.cnblogs.com/hongyj/p/9544435.html
Copyright © 2020-2023  润新知