学习笔记 - 2sat
学习笔记 - 2sat
决定重新启用Markdown……只是因为它支持MathJax数学公式
noip考完,既轻松又无奈,回来慢慢填坑
这篇博客也是拖了好久,通过kuangbin的博客才弄懂2-sat的
2-sat问题
先说sat问题——指一种每个变量只有两个值(true or false),并且给出一些限制,每个限制的基本形式为:
\(a\ XOR/OR/AND\ b\ XOR/OR/AND\ c\ (etc.) = true\)
另外当每个限制涉及的变量只有两个时,这类问题称为2-sat问题,即 \(a\ XOR/OR/AND\ b=true\),当然也可以限制值为 false,在这里a,b也可以不保证不同。求这样的问题的解,即每一个变量选或不选。
2-sat问题的建模
假设现在有N个变量形成2-sat问题。
由于一个变量要么为true,要么为false;我们可以把变量拆分成两个点——一个点表示true,另一个表示false,这样一来我们有 2N 个点,也就是 N 个点对;下面我们称 A、A' 分别表示变量A选、不选。然后我们称“一个变量的状态”为“这个状态所对应的点选或不选”。
我们可以将点连边,边(X,Y)表示选X就必须选Y;下面举两种最基本的例子:
①选变量A就必须选变量B,则连 (A,B) (B',A) 两条有向边;
②必须选变量A,则连 (A',A) 的有向边;
1-可行性问题求解
即判断某一方案是否可行。常用于检验二分答案。
通过求强连通分量求解——如果 点v 和 点v' 同时存在于一个强连通分量中,则说明从“选 变量v” 这一起点出发,可以推导出“不选 变量v”(反过来说也一样),这样就是不合法的。换句话说,点v 和 点v' 不能在同一个强连通分量中。
求强连通分量的话这里就用一个常规的方法——先从某个点出发DFS遍历能够到达的点,当退出一个DFS函数时,将当前的点压入队列中(建议手写队列,因为这里只是用来储存变量)。
上面是DFS1,每个点只能遍历一次。
然后依次访问队列中的点,然后从当前枚举到的队列中的点X出发进行DFS,将遍历到的点所属的“块”(blk)都设为与点X相同的“块”。这样一个“块”就是一个强连通分量。
最后枚举每一个变量i,检查 点i 和 点i' 是否在一个强连通分量中,如果存在,则不可行。
举个例子:HDU 3622 Bomb Game
[题意]
你需要在平面上放n个炸弹——放置第i个炸弹时,你需要在\((Ax_i,Ay_i)\)和\((Bx_i,By_i)\)两个位置中选择一个位置放置。每个炸弹的爆炸半径都是k,任意两个炸弹的爆炸范围不能重叠(可以相切)。求k最大为多少。
[解析]
很容易想到二分答案,放置第i个炸弹时选择 第一个位置 定义为“选择i”,选择第二个位置 定义为“不选择i”,这样就形成了一个2-sat问题。
根据二分出来的k可以求出重叠的炸弹,如果炸弹i与炸弹j重叠,则说明放炸弹i就不能放炸弹j,根据这个连边,2-sat判断合法性即可。
[源代码]
/*Lucky_Glass*/
#include<bits/stdc++.h>
using namespace std;
const int N=100,M=40000;
const double EPS=1e-5;
int n;
struct POINT{
int x,y;
}s[N*2+5];
inline double Dist2(int a,int b){
return 1.0*(s[a].x-s[b].x)*(s[a].x-s[b].x)+1.0*(s[a].y-s[b].y)*(s[a].y-s[b].y);
}
struct EDGE{
int to,nxt;
}edg1[M+5],edg2[M+5];
int hed1[N*2+5],hed2[N*2+5];
int cnt1,cnt2;
void AddEdge(int u,int v){ //连边,正反图都要连
edg1[cnt1].to=v;
edg1[cnt1].nxt=hed1[u];
hed1[u]=cnt1++;
edg2[cnt2].to=u;
edg2[cnt2].nxt=hed2[v];
hed2[v]=cnt2++;
}
void ClearMap(){ //清空图
memset(hed1,-1,sizeof hed1);
memset(hed2,-1,sizeof hed2);
cnt1=cnt2=0;
}
int Pop[N*2+5],blk[N*2+5];
bool vis[N*2+5];
int blkcnt;
void DFS1(int u){ //求出每个点退出DFS的顺序
vis[u]=true;
for(int i=hed1[u];i!=-1;i=edg1[i].nxt)
if(!vis[edg1[i].to])
DFS1(edg1[i].to);
Pop[++Pop[0]]=u;
}
void DFS2(int u){ //求强连通分量
vis[u]=true;blk[u]=blkcnt; //blk[i]表示i所属的联通块编号
for(int i=hed2[u];i!=-1;i=edg2[i].nxt)
if(!vis[edg2[i].to])
DFS2(edg2[i].to);
}
bool Check(){
Pop[0]=blkcnt=0;
memset(vis,false,sizeof vis);
for(int i=0;i<2*n;i++)
if(!vis[i])
DFS1(i);
memset(vis,false,sizeof vis);
for(int i=Pop[0];i>=1;i--) //按照退出顺序
if(!vis[Pop[i]]){
blkcnt++;
DFS2(Pop[i]);
}
for(int i=0;i<n;i++)
if(blk[i*2]==blk[i*2+1]) //如果不合法
return false;
return true;
}
int main(){
while(~scanf("%d",&n)){
for(int i=0;i<n;i++)
for(int j=i*2;j<=i*2+1;j++)
scanf("%d%d",&s[j].x,&s[j].y);
double lef=0,rig=40000.0;
while(rig-lef>=EPS){
double mid=(lef+rig)/2;
ClearMap();
for(int i=0;i<n*2;i++) //O(n^2)连边 :)
for(int j=i%2? i+1:i+2;j<2*n;j++)
if(Dist2(i,j)<4*mid*mid)
AddEdge(i,j^1),
AddEdge(j,i^1);
if(Check()) lef=mid;
else rig=mid;
}
printf("%.2lf\n",rig);
}
return 0;
}
(坑还没填完,下一个弄懂再写 TAT)
更新-\(2018/11/17\);终于把后面一道题弄懂了
另外一个例子……POJ 3207 Ikki's Story IV - Panda's Trick
想法比较丰富……另外写一个blog……
\(\mathcal The\ End\)
\(\mathcal Thanks\ for\ reading!\)
学习笔记 - 2sat的更多相关文章
- [学习笔记]2-SAT 问题
(本文语言不通,细节省略较多,不适合初学者学习) 解决一类简单的sat问题. 每个变量有0/1两种取值,m个限制条件都可以转化成形如:若x为0/1则y为0/1等等(x可以等于y) 具体: 每个变量拆成 ...
- OI知识点|NOIP考点|省选考点|教程与学习笔记合集
点亮技能树行动-- 本篇blog按照分类将网上写的OI知识点归纳了一下,然后会附上蒟蒻我的学习笔记或者是我认为写的不错的专题博客qwqwqwq(好吧,其实已经咕咕咕了...) 基础算法 贪心 枚举 分 ...
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- PHP-自定义模板-学习笔记
1. 开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2. 整体架构图 ...
- PHP-会员登录与注册例子解析-学习笔记
1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...
- 2014年暑假c#学习笔记目录
2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- seaJs学习笔记2 – seaJs组建库的使用
原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...
- CSS学习笔记
CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...
随机推荐
- vuex的初始化
创建store文件夹 1.功能:放异步操作 文件:actions.js 内容: 2.功能:获取state里数据 文件:getters.js 内容: export const singer = stat ...
- React Native之React速学教程(中)
概述 本篇为<React Native之React速学教程>的第一篇.本篇将从React的特点.如何使用React.JSX语法.组件(Component)以及组件的属性,状态等方面进行讲解 ...
- 基础架构之Maven私有库
Maven对于Java开发来说肯定不会陌生,由于各种问题,公司常常需要搭建自己的私有Maven仓库. (一) 环境要求 Centos 7.5.1804 Docker 18.06.1-ce sonat ...
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
viewport:移动设备上用来显示网页的那部分区域,但其大小并不局限于那部分可视区域 width设置layout viewport 的宽度,为一个正整数,或字符串"device-widt ...
- 微信小程序现实问题之低素质客户需求问题
·微信小程序已经在市场摸爬滚打很久了,但是真正是否可用以及是否真正满足客户需求,市场是否真正到了火热的程度,值得怀疑. 根据本人从事小程序开发的经验,短时间内,小程序市场依然会不温不火,而此时客户的满 ...
- react-native-echarts
react-native-echarts是react native结合百度echart的图表,集成的一个图表插件. github地址:https://github.com/zhangxinagjunH ...
- C#mail发送
这里,简单封装一个函数来发送邮件,代码如下: /// <summary> /// 邮件发送辅助类 /// </summary> public class MailHelper ...
- 在IDEA中设置方法自动注释(带参数和返回值)
第一部分 设置 打开设置面板 新建 在线模板 新建自动添加规则,注意 这里触发的字符 不能随便写 必须为 * Template text 区域 看上去有点乱,但是是为了显示时的对齐,该区域的内容如下( ...
- MyCAT详解
一.MyCAT概述 MyCAT是一款由阿里Cobar演变而来的用于支持数据库读写分离.分片的分布式中间件.MyCAT可不但支持Oracle.MSSQL.MYSQL.PG.DB2关系型数据库,同时也支持 ...
- Linux Mint 18.2安装后需要进行的设置
自己的笔记本电脑升级到win10后各种不好用,运行速度慢,开关机时间很长,系统也是经常性的更新,外加发热严重.更改设置和更换驱动都没能解决问题.另外感觉在Linux下能够更加专注,所以索性将主系统更换 ...