zoukankan      html  css  js  c++  java
  • 2-sat 部分题目

    记录一些做过的 2-sat 题目

    P4171 [JSOI2010]满汉全席

    洛谷 P4171bzoj 1823

    很裸的 2-sat
    题意:(n) 种食材,每种可以按照满式或汉式来烹饪,有 (m) 个要求,每个要求所有做出的菜品中,必须有指定的两个 满式/汉式 烹饪的第 (x) 种食材 中,至少一个
    多测

    就把每个食材,拆乘用满式和用汉式两个点,然后题目中给出的是“或”的关系,用经典 2-sat 模板的方法建图跑 tarjan 就行
    其实 满式和汉式 对应的就是经典模型中的 真和假

    代码

    P5782 [POI2001]和平委员会

    洛谷 P5782

    每个党在议会中有 (2) 个代表。代表从 (1) 编号到 (2n)。 编号为 (2i-1)(2i) 的代表属于第 (i) 个党派。
    选一些人当代表,满足:

    • 每个党派都在委员会中恰有 (1) 个代表。
    • 如果 (2) 个代表彼此厌恶,则他们不能都属于委员会。

    给出互相厌恶的信息,求是否有满足要求的选法,如果有,升序输出任意一种

    也是显然的 2-sat
    对于给出的互相厌恶的两个人,先判一下在他们在自己的党派中分别是第几个人
    对于每个党,拆成两个点,然后每个点代表是选第一个人还是选第二个
    连边的依据就是,如果选了这个人,一定要再选哪个人

    我的写法中是,每个党中第一个人用 (1)(n),编号,第二个人用 (n+1)(2n) 编号
    给出的信息的连边方式是,对于互相厌恶的每一方,都向对方的党派中,的另一个人连边,表示如果选择这个人,在对方党派中,就必须选另一个人(因为不能同时选这个人和对方)

    然后跑 tarjan 就行了
    代码

    P6378 [PA2010]Riddle

    洛谷 P6378

    (n) 个点 (m) 条边的无向图被分成 (k) 个部分。每个部分包含一些点。
    请选择一些关键点,使得每个部分 至多 有一个关键点,且每条边 至少 有一个端点是关键点。

    比上面两个稍微难点
    还是把每个点拆成两个,分别表示这个点选为关键的还是不选
    (1,cdots ,n) 的编号表示选,(n+1,cdots ,2n) 的编号表示不选

    首先考虑第二条限制,每条边 至少 有一个端点是关键点
    ((u+n,v),(v+n,u)) 两条边,表示一段如果不选,一定能导出另一端要选

    再考虑第一种,首先有种朴素的想法,就是每一个点,设为 (x),设和它在同一个部分内的点编号分别是 (a_i),用 (x) 分别向 (a_i+n) 连边
    就是如果 (x) 被选了,一定能导出 (a_i) 都不能选
    但边数达到了 (n^2),不可行

    可以用一种 前缀和优化,以前并没有听说过这种方法,还是看来题解才知道的
    要新建一堆点,(pre_i) 表示在当前的这个部分,前 (i) 个点中,有一个点已经被选了,而 (pre_i') 表示前 (i) 个点,一个都没被选
    然后也是用 2-sat 的连边规则,假设某个点表示的信息成立,那么就用它,连向由它表示的这个信息,一定能导出的信息,所对应的点

    具体的连边方式比较复杂,可以想到,如果当前在考虑一个部分的第 (i) 个点,与它有关的有 (a_i,a_i',pre_i,pre_i',pre_{i-1},pre_{i-1}'),这里是用 (a_i,a_i') 分别表示代表信息第 (i) 个点 选/不选 的点
    然后如果很懵的话可以 (6 imes 5=30) 次两两分别枚举,看一下有没有关系,看起来麻烦,其实有好多一想就知道没关系的可以直接跳过了
    下面的括号表示连边,是有向的

    • ((a_i,a_i'),(pre_i,pre_i'),(pre_{i-1},pre_{i-1}')),这些并不在 2-sat 连边考虑范围内,然后把他们反过来也是一样
    • ((a_i,pre_i),(a_i,pre_{i-1}')),选了第 (i) 个,前 (i) 个中有被选的,前 (i-1) 个没有
    • (a_i',pre_i,pre{i-1}'),这三个信息并不能推出什么,所以没有它们的出边
    • ((pre_i',a_i'),(pre_i',pre_{i-1}')),显然
    • ((pre_{i-1},pre_i),(pre_{i-1},a_i')),前 (i-1) 个中有被选的,前 (i) 个肯定也有,且第 (i) 个不能选

    就可以了,题目也并没有要求给出方案
    代码中,用 (1)(n) 表示 (a_i)(n+1)(2n) 表示 (a_i')(2n+1)(3n)(pre_i)(3n+1)(4n)(pre_i')
    代码

    P3825 [NOI2017]游戏

    洛谷 P3825bzoj 4945


    (nle 5cdot 10^4,mle 10^5,dle 8)

    如果没有 ( exttt{x}) 地图,那么对于每一场比赛,都只能使用两种车子
    那么对每个比赛,可以用两个点,分别表示对于当场比赛,用的是能用的车子中的第几个(比如一场比赛不能用 ( exttt{A}),那么 ( exttt{B}) 就是第一个,( exttt{C}) 就是第二个
    直接按 2-sat 建图跑 tarjan
    考虑如何建图,下面描述中,字母意义就对应了题目中游戏要求描述的四元组中的字母,设第 (i) 个比赛不能用车 (s_i)

    • (s_i=h_i),不能用 (h_i),说明这种情况永远不会发生,直接忽略就行
    • (s_j=h_j)(j) 比赛不能用 (h_j),说明我们不能让这种情况发生,否则就违反了规则,那么由 (h_i),向连边比赛 (i) 能用的另一个车连边,表示如果用车 (h_i) 成立(这是不符合我们要求的),就要强制它选另一辆,也就是让另一个车成立
    • 其它情况。由 (h_i)(h_j) 连边就行,意义就是题目中要求的,(i)(h_i)(j) 必须用 (h_j)

    如果 tarjan 判断成立,按照 tarjan 缩点时强连通分量与拓扑序相反的性质,就能构造出一组解

    那么有地图 ( exttt{x}) 怎么办?
    由于 ( exttt{x}) 很少,所以可以 (2^d) 枚举每一个 ( exttt{x})( exttt{a})( exttt{b}),这样分别能使用 ( exttt{A,B}) 车和 ( exttt{B,C}) 车,包含所有情况,就不用考虑 ( exttt{x}) 是地图 ( exttt{c}) 的情况了

    所以复杂度 (O(2^dm)),洛谷bzoj都能过,但uoj加了一组恶心的extra,被卡成了97,把递归改成循环再加上火车头还是不行/kk
    代码

    P3513 [POI2011]KON-Conspiracy

    洛谷P3513

    Byteotia 的领土被占领了,国王 Byteasar 正在打算组织秘密抵抗运动。国王需要选一些人来进行这场运动,而这些人被分为两部分:
    一部分成为同谋者活动在被占领区域,另一部分是后勤组织在未被占领的领土上运转。但是这里出现了一个问题:

    • 后勤组织里的任意两人都必须是熟人,以促进合作和提高工作效率。
    • 同谋者的团体中任意两人都不能是熟人。
    • 每一部分都至少要有一个人。

    国王想知道有多少种分配方案满足以上条件,当然也有可能不存在合理方案。

    比较有思维难度,思路来自这个blog:https://www.cnblogs.com/chenyushuo/p/5128665.html

    首先,可以用一个很显然的 2-sat 求出一种安排方式,具体方法是 (i) 认识 (j),就连边 (i+n,j),否则连 (i,j+n)
    其中 (1cdots n) 是后勤,(n+1cdots 2n) 是同谋

    然后从这种方式看看能转变成几种其它方式,显然不能同时让两个人从一个集合到另一个集合(比如两个互相认识的后勤同时到了同谋,那么它们互相认识就出现了问题)
    所以转换方式是,一个人自己转变集合,或者两个集合交换一个人

    首先定义 (x) 的“冲突点”,如果 (x) 是后勤,那么冲突点是在同谋中的 (x) 认识的人,如果 (x) 在同谋,冲突点是在后勤中 (x) 不认识的人
    (x) 的冲突点个数为 (num_x)

    • (num_x>1),则无法让 (x) 到另一个集合
    • (num_x=1),需要交换 (x) 和他的唯一一个冲突点,但是如果它的冲突点的 (num) 不为 (0),也不能交换(两个点显然不能互为冲突点,那么如果它的冲突点也有冲突点,就肯定和它的集合内的某个点冲突,除非和这个冲突的点互换,它的冲突点是不能来的它的集合的)
    • (num_x=0),可以直接把 (x) 放到对面(如果 (x) 所在集合大小大于 (1)),也可以和对面某个冲突点个数为 (0) 的点呼唤

    最后这个两个集合中,冲突点为 (0) 的点互换产生的答案,可以拿两遍冲突点个数为 (0) 的点的个数一相乘得到
    可以想到,这样统计答案包含了所有情况

    代码

    POJ2749 Building roads

    给出一些点和它们的坐标,以及两个链接点,所有点都要链接到恰好一个链接点上
    给出 (A) 对点,这些点任意一对不能链接同一个链接点。还有 (B) 对点,任意一对必须连接到一个链接点
    问有没有可行方案,如果有,两个点之间最大距离的最小值是多少,距离按曼哈顿距离计算

    每个点拆成 连到第一个点 和 连到第二个点,然后二分一个最大距离,就可以得到关于距离的限制条件,连边即可

    代码

    LOJ#6036.「雅礼集训 2017 Day4」编码
    P5332 [JSOI2019]精准预测
    这俩题细节好像挺多,做了一上午没做出来自闭了/kk
    LOJ#571.「LibreOJ Round #11」Misaka Network 与 Accelerator,一开始以为是个线段树优化连边的题,后来写着写着发现不对,看网上说要用边分治,之后应该就要学这一块了,到时候应该会补

    然而难度稍大的我似乎都没做qaq

  • 相关阅读:
    【一些思路】web和app测试的区别
    【Python】I/O和比赛的其他一些问题
    【Python】迭代器和生成器的个人理解,再讲一讲协程
    【TCP/IP】如果打不开一个网页,需要如何处理?
    DOM事件
    GASP动画的基本使用
    Velocity的使用方法
    Swiper和Swiper Animate使用方法
    DOM操作
    JavaScript函数
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/12833350.html
Copyright © 2011-2022 走看看