首页 > 其他分享 >2-sat问题

2-sat问题

时间:2022-09-21 19:14:02浏览次数:47  
标签:tot int dfs 问题 maxn low quad sat

什么是2-sat问题

如给定\(n\)个变量,可以赋值为\(A{_{0} }\)或\(A{_{1} }\),现给出\(m\)个限制,询问是否存在合法赋值使得\(m\)个询问均成立
很抽象吧

举个例子

现在有\(n\)个水果,有\(m\)个人,他们每一个人会有两种需求,他们可能会需要第\(i\)种,也可能讨厌第\(j\)种

小A 讨厌\(a\) 喜欢\(b\)
小B 喜欢\(a\) 喜欢\(b\)
小C 讨厌\(a\) 讨厌\(b\)

显然无论如何选择\(ab\)都无法满足他们

我们不妨把两种要求设为 a,b,,变量前加 ¬ 表示「不」,即「假」。上述条件翻译成布尔方程即:\((¬ a∨b)\quad(a∨b)\quad(¬a∨¬b)\)

怎么求解 2-SAT 问题?

使用强连通分量

对于每个变量 \(x\),我们建立两个点:\(x\quad¬x\), 分别表示变量 \(x\) 取 \(true\) 和取 \(false\)。所以,图的节点个数是两倍的变量个数。在存储方式上,可以给第 \(i\) 个变量标号为 \(i\),其对应的反值标号为 \(i+n\)。对于每个同学的要求 \((a∨b)\),转换为 \(¬a→b∧¬b→a\)。对于这个式子,可以理解为:「若 \(a\)不选则 \(b\) 必选,若 \(b\) 不选则 \(a\) 必选」然后按照箭头的方向建有向边就好了。综上,我们这样对上面的方程建图:

原式 \(\quad\quad\)建图
\((¬ a∨b)\quad a→b∧¬b→¬a\)
\((a∨b)\quad ¬a→b∧¬b→a\)
\((¬a∨¬b)\quad a→¬b∧b→¬a\)
说白了就是其中一个若不满足则另一个必须满足要求
建出来就长这样
image
通过图我们可以发现如果\(a\)成立则\(¬a\)也成立,这显然矛盾
那么我们通过一个强连通分量就可以判断矛盾情况是否可以相互到达

有了前置芝士,我们就可以看一道例题了

满汉全席

显然,\(n\)种肉相当于分别赋值为
对于\(j\) 评委(如汉式牛肉满式羊肉)
就可以转化为 满式牛肉--->满式羊肉汉式羊肉--->汉式牛肉
( 类比上述\((¬ a∨b)\) )

建好图后,开始\(Tarjan\)求强连通分量。可知,同一强联通分量中的菜不能包括同种肉的两种做法,否则,答案为\(BAD\)。所以求出强连通分量后,求可以立刻得出答案。
image
(样例一的建图)

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define maxn 100010 
using namespace std;
int head[maxn],low[maxn],dfs[maxn],Gro[maxn];
int vis[maxn];
int f,tot,cnt,group,num1,num2;
stack<int> q;
struct node{
	int v,nex;}re[maxn];
void add(int u,int v)
{
	++tot;
	re[tot].v=v; re[tot].nex=head[u];
	head[u]=tot;
}
void init()
{
	memset(head,0,sizeof head);
	memset(Gro,0,sizeof Gro);
	memset(dfs,0,sizeof dfs);
	memset(vis,0,sizeof vis);
	memset(low,0,sizeof low);
	f=tot=cnt=group=0;
	num1=num2=0;
}
void tarjian(int x)
{
	low[x]=dfs[x]=++cnt;
	q.push(x);  vis[x]=1;
	for(int i=head[x];i;i=re[i].nex)
	{
		int v=re[i].v;
		if(!dfs[v])
		{
			tarjian(v);
			low[x]=min(low[x],low[v]);
		}
		else if(vis[v])
		low[x]=min(low[x],dfs[v]);
	}
	if(low[x]==dfs[x])
	{
		int y;
		group++;
		do{
			y=q.top();
			q.pop(); vis[y]=0;
			Gro[y]=group;
		}
		while(y!=x);
	}
}

int T,n,m,k;
char s1[10],s2[10];
signed main()
{
	scanf("%lld",&T);
	while(T--)
	{
		scanf("%lld%lld",&n,&m);
		init();
		for(int i=1;i<=m;i++)// m  1~n     h  n+1~2n
		{
			cin>>s1>>s2;
			k=1,num1=0;
			while(s1[k]>='0'&&s1[k]<='9') num1=num1*10+s1[k++]-'0';
			k=1,num2=0;
			while(s2[k]>='0'&&s2[k]<='9') num2=num2*10+s2[k++]-'0';
			if(s1[0]=='m')
			{
				if(s2[0]=='m') add(num1+n,num2),add(num2+n,num1);//分别是将h1连m2  同时将h2连m1 
				if(s2[0]=='h') add(num1+n,num2+n),add(num2,num1);//将h1连h2   同时将m2连m1 
			}
			if(s1[0]=='h')
			{
				if(s2[0]=='m') add(num1,num2),add(num2+n,num1+n);
				if(s2[0]=='h') add(num1,num2+n),add(num2,num1+n);
			}
		}
		
		for(int i=1;i<=2*n;i++)
		{
			if(!dfs[i]) tarjian(i);
		}
		for(int i=1;i<=n;i++)
		{
			if(Gro[i]==Gro[i+n]) 
			{
				f=1; break;
			}
		}
		
		if(f==1) printf("BAD\n");
		else printf("GOOD\n");
	}
	return 0;
}
/*
2
3 4 
m3 h1 
m1 m2 
h1 h3 
h3 m2 
2 4 
h1 m2 
m2 m1 
h1 h2 
m1 h2

*/

标签:tot,int,dfs,问题,maxn,low,quad,sat
From: https://www.cnblogs.com/llwwll/p/16716804.html

相关文章

  • 9.21课上问题与思考
    在本周的Java课上我获得了以下的思考与感受一、懒人造就了方法对于相同的开山一事,愚公和李冰有不同的方式去处理。愚公选择一点点去凿山,靠日积月累的努力去完成目标,李冰......
  • gateway跨域问题最优解
    解决跨域问题的方案有很多,比如配置全局配置类跨域等等...综合对比所有的跨域问题解决方式,还是觉得修改配置文件最简单,分享下来给需要的人。spring:application:n......
  • 关于for循环的key 有时候会出现一些不可预估的问题
    在写项目中遇到这样一个问题:  第一种情况:v-for循环里面套v-for再删除里面循环的某一项是总是删除最后一项。下标打印的都是正确的返回的数据也是正常删除的,但是......
  • CAN分析仪时间显示问题
    不知道大家有没有用过USB-CAN分析仪,最近用被坑了,我用分析仪接收10ms周期的报文,但是分析仪上总断续显示同一时间接收两帧报文,我一度怀疑我的报文发送代码问题。找到最后,发......
  • cdh环境:hue集成kerberos无法启动ktr问题处理过程
    cdh版本:ClouderaExpress6.1.0报错现象:Ifthe'renewuntil'dateisthesameasthe'validstarting'date,theticketcannotberenewed.PleasecheckyourKDCco......
  • ScrewUtil - NullPointer问题
    一、问题描述使用ScrewUtil导出PostgreSQL的表结构时,报错NullPointer; 二、问题排查首先,ScrewUtil确实很好用,之前导出mysql的表一点问题没有;而且只需要一些简单的配置,r......
  • DevExpress GridControl单元格内添加下拉框空白问题(转)
    按语:dt.Columns.Add("freq");  前几天使用Winform版的GridControl控件做表格,给单元格添加下拉框出了问题,内容空白,不显示任何东西。原因是用于展示下拉选项的辅助类中,字......
  • 使用linux时遇到的问题,ifconfig -a 报错不能找到命令,提示下载。
    1.问题截图    2.解决办法首先查看占用的进程  然后杀死进程  接下来输入如下命令  当前......
  • FCKEditor粘贴word图片问题解决
    ​ 当前功能基于PHP,其它语言流程大致相同 1.新增上传wordjson配置在ueditor\php\config.json中新增如下配置:     /* 上传word配置 */    "wordAction......
  • Android 11 高版本 出现外部存储无法访问的问题
    问题起因:安卓11,同一个APK, 安装后在本地Download目录创建了一个文件, 然后卸载这个APK。在重新安装这个APK,之前创建的文件就不能访问。签名我这边也设置过的,也还是一样的......