热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

学习笔记2sat

学习笔记-2sat决定重新启用Markdown……只是因为它支持MathJax数学公式noip考完,既轻松又无奈,回来慢慢填坑这篇博客也是拖了好久&#x

学习笔记 - 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
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]&#61;blkcnt&#61;0;memset(vis,false,sizeof vis);for(int i&#61;0;i<2*n;i&#43;&#43;)if(!vis[i])DFS1(i);memset(vis,false,sizeof vis);for(int i&#61;Pop[0];i>&#61;1;i--) //按照退出顺序if(!vis[Pop[i]]){blkcnt&#43;&#43;;DFS2(Pop[i]);}for(int i&#61;0;i}int main(){while(~scanf("%d",&n)){for(int i&#61;0;i&#61;EPS){double mid&#61;(lef&#43;rig)/2;ClearMap();for(int i&#61;0;i}

(坑还没填完&#xff0c;下一个弄懂再写 TAT)
更新-\(2018/11/17\)&#xff1b;终于把后面一道题弄懂了

另外一个例子……POJ 3207 Ikki&#39;s Story IV - Panda&#39;s Trick

想法比较丰富……另外写一个blog……


\(\mathcal The\ End\)

\(\mathcal Thanks\ for\ reading!\)


转:https://www.cnblogs.com/LuckyGlass-blog/p/9965950.html



推荐阅读
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 本文介绍了Codeforces Round #321 (Div. 2)比赛中的问题Kefa and Dishes,通过状压和spfa算法解决了这个问题。给定一个有向图,求在不超过m步的情况下,能获得的最大权值和。点不能重复走。文章详细介绍了问题的题意、解题思路和代码实现。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • Java 11相对于Java 8,OptaPlanner性能提升有多大?
    本文通过基准测试比较了Java 11和Java 8对OptaPlanner的性能提升。测试结果表明,在相同的硬件环境下,Java 11相对于Java 8在垃圾回收方面表现更好,从而提升了OptaPlanner的性能。 ... [详细]
  • 本文介绍了使用Python编写购物程序的实现步骤和代码示例。程序启动后,用户需要输入工资,并打印商品列表。用户可以根据商品编号选择购买商品,程序会检测余额是否充足,如果充足则直接扣款,否则提醒用户。用户可以随时退出程序,在退出时打印已购买商品的数量和余额。附带了完整的代码示例。 ... [详细]
  • 实现一个通讯录系统,可添加、删除、修改、查找、显示、清空、排序通讯录信息
    本文介绍了如何实现一个通讯录系统,该系统可以实现添加、删除、修改、查找、显示、清空、排序通讯录信息的功能。通过定义结构体LINK和PEOPLE来存储通讯录信息,使用相关函数来实现各项功能。详细介绍了每个功能的实现方法。 ... [详细]
  • LeetCode笔记:剑指Offer 41. 数据流中的中位数(Java、堆、优先队列、知识点)
    本文介绍了LeetCode剑指Offer 41题的解题思路和代码实现,主要涉及了Java中的优先队列和堆排序的知识点。优先队列是Queue接口的实现,可以对其中的元素进行排序,采用小顶堆的方式进行排序。本文还介绍了Java中queue的offer、poll、add、remove、element、peek等方法的区别和用法。 ... [详细]
  • 本文介绍了指针的概念以及在函数调用时使用指针作为参数的情况。指针存放的是变量的地址,通过指针可以修改指针所指的变量的值。然而,如果想要修改指针的指向,就需要使用指针的引用。文章还通过一个简单的示例代码解释了指针的引用的使用方法,并思考了在修改指针的指向后,取指针的输出结果。 ... [详细]
  • 网卡工作原理及网络知识分享
    本文介绍了网卡的工作原理,包括CSMA/CD、ARP欺骗等网络知识。网卡是负责整台计算机的网络通信,没有它,计算机将成为信息孤岛。文章通过一个对话的形式,生动形象地讲述了网卡的工作原理,并介绍了集线器Hub时代的网络构成。对于想学习网络知识的读者来说,本文是一篇不错的参考资料。 ... [详细]
author-avatar
ex7776647
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有