首页 > 其他分享 >2-SAT 学习笔记

2-SAT 学习笔记

时间:2024-08-10 11:41:30浏览次数:6  
标签:bj 一条 联通 int neg 笔记 学习 tot SAT

2-SAT 用于求解布尔方程组,其中每个方程最多含有两个变量,方程的形式为 \((a∨b)=1\) ,即式子 \(a\) 为真或式子 \(b\) 为真。求解的方法是根据逻辑关系式建图,然后求强联通子图,每一个强联通子图的答案都是一样的。

建图:

这里以模版题为例:

题意:给定若干个需要满足的条件,其形式为 \(a,1/0,b,1/0\) ,表示要求 \(a\) 为真/假 或 \(b\) 为真/假。

我们将一个点拆成两个 \(a\) 和 \(\neg a\) ,分别表示 \(a\) 取真和取假。然后根据方程式,建一个有向图,其中有向边 \(a\to b\) 的定义为:若 \(a\) 被满足,则 \(b\) 也要被满足。一共有四种可能的情况:

  • 若 \(a\) 为真或 \(b\) 为真:则当 \(a\) 为假时,\(b\) 一定为真,将 \(\neg a\) 向 \(b\) 连一条有向边;当 \(b\) 为假时,\(a\) 一定为真,将 \(\neg b\) 向 \(a\) 连一条有向边。
  • 若 \(a\) 为真或 \(b\) 为假:则当 \(a\) 为假时,\(b\) 一定为假,将 \(\neg a\) 向 \(\neg b\) 连一条有向边;当 \(b\) 为真时,\(a\) 一定为假,将 \(b\) 向 \(\neg a\) 连一条有向边。
  • 若 \(a\) 为假或 \(b\) 为真:则当 \(a\) 为真时,\(b\) 一定为真,将 \(a\) 向 \(b\) 连一条有向边;当 \(b\) 为假时,\(a\) 一定为假,将 \(\neg b\) 向 \(\neg a\) 连一条有向边。
  • 若 \(a\) 为假或 \(b\) 为假:则当 \(a\) 为真时,\(b\) 一定为假,将 \(a\) 向 \(\neg b\) 连一条有向边;当 \(b\) 为真时,\(a\) 一定为假,将 \(b\) 向 \(\neg a\) 连一条有向边。

注意连边建图时,一定要将所有的情况全部连起来,并且一定要满足 若 \(a\) 满足,则一定可以推倒 \(b\) 满足。

求强联通子图:

这里介绍 Kosaraju 算法。

该算法分为两步:

  1. 先对原图中任意一个点开始进行 dfs ,直到所有点都被访问过一遍。在 dfs 时,当我们每退出一个点时,就将该点放入一个栈内。
  2. 在原图的反图(即将所有 \(A\to B\) 的有向边变成 \(B\to A\) )上进行 dfs 。从上一步中得到的栈的栈顶开始,每次遇到一个没有被遍历过的点,就遍历该点,此时该点所能到达的所有点即为一个强联通子图。

求答案:

由于每个点只能选 真或假 ,而同一个联通块中的所有点都是同样的值。所以当某个点的真和假都出现在同一个联通块中,则无解。随便选一个联通块,并将其中的点都作为答案就可以了。

但是这样还有一个问题,如下图:

image

此时我们无论选第一个联通块还是第二个联通块都是可行的,但是当我们再加上一条 \(B\to !C\) 的边,同时也会加上新的一条 \(C\to !B\) 的边。这时我们就不能取联通块 \(A,B,C,D\) 了。

image

这时根据上面我们求联通块的算法,若对于两个点之间只存在一条有向边 \(a\to b\) ,我们在遍历反图时会先遍历 \(a\) ,此时边反向变成了 \(b\to a\) ,然后 \(a\) 就无法达到 \(b\) ,所以 \(b\) 所在的联通块的编号会大于 \(a\) 所在的联通块,这样我们通过取编号最大的那个联通块里的点就可以避免上面这种问题。

Code:

#include<cstdio>
using namespace std;
const int N=1e6+5;
int n,m,tot,he[N*2],ne[N*2],to[N*2],he1[N*2],ne1[N*2],to1[N*2],d[N*2],ti,co[N*2];bool bj[N*2];
void add(int x,int y)
{
	tot++;ne[tot]=he[x];to[tot]=y;he[x]=tot;
	ne1[tot]=he1[y];to1[tot]=x;he1[y]=tot;
}
void dfs1(int x)
{
	int i,y;
	bj[x]=1;
	for(i=he[x];i!=0;i=ne[i])
	{
		y=to[i];
		if(bj[y]==0)
		dfs1(y);
	}
	d[++ti]=x;
}
void dfs2(int x)
{
	int i,y;
	co[x]=ti;bj[x]=1;
	for(i=he1[x];i!=0;i=ne1[i])
	{
		y=to1[i];
		if(bj[y]==0)
		dfs2(y);
	}
}
void Kosaraju()
{
	int i;
	for(i=1;i<=2*n;i++)
	{
		if(bj[i]==0)
		dfs1(i);
	}
	for(i=1;i<=n*2;i++)
	bj[i]=0;
	ti=0;
	for(i=n*2;i>=1;i--)
	{
		if(bj[d[i]]==0)
		{
			ti++;dfs2(d[i]);
		}
	}
}
int main()
{
	int i,x,y,bj1,bj2;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d%d",&x,&bj1,&y,&bj2);
		add(x+n*bj1,y+n*(bj2^1))
		;add(y+n*bj2,x+n*(bj1^1));
	}
	Kosaraju();
	for(i=1;i<=n;i++)
	{
		if(co[i]==co[i+n])
		{
			printf("IMPOSSIBLE");
			return 0;
		}
	}
	printf("POSSIBLE\n");
	for(i=1;i<=n;i++)
	{
		if(co[i]>co[i+n])
		printf("1 ");
		else
		printf("0 ");
	}
	return 0;
}

标签:bj,一条,联通,int,neg,笔记,学习,tot,SAT
From: https://www.cnblogs.com/Cyanwind/p/18352102

相关文章

  • 大一暑假学习记录6
    这一周我基本完成了刘立嘉老师布置的暑假作业,其中通讯录的录入与显示,整数分解为若干项之和是我认为最难做的题目,前者的难点是sample有查询越界、最大N,反复查询同一记录等等。后者则是样例等价,多行输出难以解决。于是我又重新学习了结构体部分的内容,定义了Contact结构体来存储......
  • 学生Java学习路程-6
    ok,到了一周一次的总结时刻,我大致会有下面几个方面的论述:1.这周学习了Java的那些东西2.这周遇到了什么苦难3.未来是否需要改进方法等几个方面阐述我的学习路程。复习面向对象数组数组的三种初始化方法:默认,静态,动态引用类型Man放入数组中的测试代码数组的拷贝使用规范使......
  • Lazysysadmin靶机笔记
    Lazysysadmin靶机笔记概述lazysysadmin是一台Vulnhub靶机,整体比较简单,要对一些存在服务弱口令比较敏感。靶机地址:https://pan.baidu.com/s/19nBjhMpGkdBDBFSnMEDfOg?pwd=heyj提取码:heyj一、nmap扫描1、主机发现#-sn只做ping扫描,不做端口扫描sudonmap-sn192.168.247.1......
  • 爆火下28万次!MIT最新-理解深度学习
        最近疯传的-理解深度学习-高达28万次,被认为可能。涵盖了深度学习从基础到高级各个方面的内容,包括基本概念、监督学习、强化学习、线性回归、神经网络、扩散模型等等。全面系统地机器学习的基础概念和深度学习的多种模型,还包括最新的Transformer和图神经网络。 免......
  • 谷粒商城实战笔记-145-性能压测-性能监控-jvisualvm使用-解决插件不能安装
    文章目录jvisualvm的作用安装查看gc相关信息的插件解决jvisualvm不能正常安装插件的问题1,查看java版本2,打开网址3,修改jvisualvm的设置jvisualvm的作用JVisualVM是一个集成在JavaDevelopmentKit(JDK)中的多功能工具,它提供了一种可视化的方式来监控和分析Java应用......
  • 【编程笔记】解决移动硬盘无法访问文件或目录损坏且无法读取
    解决移动硬盘无法访问文件或目录损坏且无法读取只解决:移动硬盘无法访问文件或目录损坏且无法读取问题由于频繁下载数据,多次安装虚拟机导致磁盘无法被系统识别。磁盘本身是好的,只是不能被识别,如果将磁盘格式化,就可以正常使用,这样磁盘内数据就丢失了。怎样才能即保留数据......
  • 【ACM出版,见刊检索快速稳定】第四届物联网与机器学习国际学术会议(IoTML 2024,8月23-25)
    2024年第四届物联网与机器学习国际学术会议(IoTML2024)将于2024年8月23-25日在中国南昌召开。会议将围绕着物联网和机器学习开展,探讨本领域发展所面临的关键性挑战问题和研究方向,以期推动该领域理论、技术在高校和企业的发展和应用,为专注于该研究领域的创新学者、工程师和......
  • 《大学新生编程入门指南:选择适合自己的编程语言和制定有效学习计划》
    编程小白如何成为大神?大学新生的最佳入门攻略编程已成为当代大学生的必备技能,但面对众多编程语言和学习资源,新生们常常感到迷茫。如何选择适合自己的编程语言?如何制定有效的学习计划?如何避免常见的学习陷阱?让我们一起探讨大学新生入门编程的最佳路径,为你的大学生活和未来职业......
  • 学习Java第六周
    本周学习——面向对象(下)一、包装类Integer——intLong——longShort——shortByte——byteFloat——floatDouble——doubleCharacter——charBoolean——boolean二、处理对象1.和equals方法Java程序测试两个变量是否相等有两种方式:一种是利用运算符;另一种是利用equals......
  • Java学习记录第六周
    今天在进行数组反转时第一次用了这个代码![](https://img2024.cnblogs.com/blog/3475598/202408/3475598-20240808230516048-1627660110.png)没有考虑到第一个循环只进行一次时,第二个循环进行完一轮了。第二次用了这个代码没有考虑到数组直接赋值会使原先的值丢失,所以最后又定......