排除等效冗余
概述
排除等效冗余,是一个范围很广的概念,大到算法思想的设计,小到对题目的转化。但不可否认,这种思想在做题中经常出现。往往出题人整选手,会将题目出的复杂一点。事实上,很多条件都是没用的或者可以被简单代替的,但若不排除这些冗余条件,将给做题带来较大影响。所以,这种思想方法必须掌握。
本文将从排除等效冗余的角度对每道例题进行重点剖析,至于其他过程,可以详见博客。
对无用状态的去除
感觉很熟悉,对吧?没错,在学习搜索剪枝时,我们常用到这种优化思想,分别称为最优性剪枝和可行性剪枝。
最优性剪枝,即从最优化的角度考虑剪枝:如果当前计算的答案已经没有之前的答案优,再计算下去一定不会更优,可以直接终止这次的搜索,考虑其他计算。
这是在搜索剪枝中的应用。其实在平时做题中也经常出现,比如:有 和 两种选择,其中 无论从自身对答案的贡献,还是帮助其他值对答案的贡献来看,都是最优的,那么我们可以只保留 而将 去掉,毕竟 明显更劣。
这和单调队列也很像,如果一个值更优还更靠前(前还是后依题目而定),那么必然将其他值踢掉,保留当前值
我们来看几道关于最优性优化的题目(不包括单调队列和搜索)。
最优性优化
T1
有 块白色或黑色的石头排成一排,第 块石头的重量为 。你每次可以取走一块石头。如果这块石头不在最左侧或最右侧,并且和它相邻的两块石头的颜色均与它自己的颜色不同,你可以获得 分;否则,你不得分。两块石头是相邻的当且仅当它们之间没有还没被移走的石头。你要求出你的最大得分。
可以发现,对于一段连续的形如 WWWW 这样的一堆颜色相同石子,我们只保留其中权值最大的一定是最优的,我们考虑从石子对别人的贡献和本身对答案的贡献进行分析。
由题知,只有相邻的石子与自己颜色不相等,取的时候才能得分。所以从对答案的贡献来看,一堆石子(数量记作 )一定是先取走 个不得分的,再取走一个得分的,显然我们要让最后一个能得分的权值尽量大,即最后取走的是这个石子中的最大值。
那么,只保留一个石头,会对相邻其他颜色石头的选取造成影响吗?
显然不会,对于 BWWWWB
和 BWB
来讲,可以先选取两边的B
,最后选取中间的W
,所以只保留一个不会对其他答案的选取造成影响。
经过一波简单的转化,将字符串转化为了WBWBWBWB
这种颜色交替的字符串,然后简单分析性质就可以做。
T2
给定一个长为的正整数序列
求 的一个长度为 的子序列 ,并且最小化
求出 的最小值。
幼儿园都看的出来的二分答案。。。
我们考虑如何进行check
。
对于相邻的 而言,若 ,且 ,我们应该选择那个进 呢?
从对合法序列长度的贡献来看,选择 和选择 的贡献都是 ,我们考虑两个选择对数组其他位置的选择的影响。
由贪心可得,如果选择 ,那么后面更容易满足 的条件,所以我们可以得出一个结论,选择 一定不比选择 劣。
由此可以得出算法:按照上述思路不断合并相邻不合法的两项,可以用链表或者双端队列实现。我用的是双端队列。
可行性优化
其实可行性优化不仅仅表现为对代码的优化,也表现为对算法时间复杂度的分析,往往确认时间复杂度不是建容易的事(尤其是记忆化搜索这种玄学算法)。
来看几道题。
T1
现在有一个 的格子大小的木板,大王想用 的多米诺骨牌把格子填满。大王不满足于普通的填法,大王还想让每个格点都不能被 个多米诺骨牌顶点覆盖。
问有多少种填的方式。
乍一看非常复杂。二维计数题, ,显然不能用正常的 思路。注意,在山穷水尽之时,我们就要考虑一个问题:是否存在无用的状态呢?
通过手模我们可以算出,合法的矩形只有行数为 的,两个行数不为 的矩形拼在一起是不合法的。这样我们就将二维问题转化为一维问题。然后进行简单的递推即可。
T2
给定参数 ,以及 ,进行 次操作,第 次操作可以选择保留 的倍数或者去掉 的倍数。先手希望操作完权值和最小,后手希望操作完权值和最大。问最终的权值。
乍一看,题目很难,用正常的 或者贪心都不太好搞,因为我们很难不维护当前的数集 ,但是维护数集 意味着空间时间绝对爆炸(毕竟 ),对于这种看上去不可做题,一般而言,要么是答案很少,要么是算到一定程度答案是恒定的。
考虑暴力怎么做,按照博弈论的套路,暴力的枚举每一步的决策,设 表示现在在进行第 轮,数集是 ,算出的权值。如果是先手,就走向对手取到最小值的路径;反之亦然。
那我们考虑,假设是 倍数的有 个,不是的有 个, 如果取多的那边,那么每次数集的大小就会减半,只需进行 次操作就可以将数集取空,那么由于一个人想让结果变大,另一个人相反,于是若先手取了减少后少的那一边,后手就会取减少后多的那一边,整理一下,最多经过 次操作,就能将数集取空,答案为 .
所以在感觉状压不行,贪心不行, 爆搜也不行的情况下,就要坚信出题人在出 诈 骗 题 。
T3
洛谷月赛的题,想了 分钟发现不对路,答案只会是 其中一个, 的情况很好判断,所以只需要判断 的情况即可。可以很套路的枚举中间折点,也就是 个折点中唯一一个不在坐标轴上的那个。然后统计对应矩形内的点的数量即可,是个二维偏序问题,树状数组即可。直接枚举容易超时,用二分即可。
T4
Cuber QQ 有一个长度为 的数列 ,其中有一些位置 Cuber QQ 已经填上了数。
对于空着的位置 Cuber QQ 想考验一下 Little Fang,他希望 Little Fang 在空白位置填上一些数后,使得这个数列的任意连续子序列的和都是质数,也就是说,
出的题,这个出题人最喜欢用诈骗题阴人,你看,又来了。。。
回归正题,发现与质数有关的算法其实不多,要使得任意区间内的数字和都为质数, 和贪心看上去都不好做,我们考虑会不会出现无解等情况。
首先,每个位置上必须是质数(长度为 的区间),接着研究相邻的情况,发现,如果两个质数都是奇数,那么加一起是偶数,不满足题目条件,所以要用到唯一的偶质数 ,并且在序列中一定是交替出现的,像这样子(设 是奇质数):
接着考虑长度为 的序列,发现如果是 “奇质数 2 奇质数” 这样的排布,加起来还是会得到偶数(不合法),所以唯一合法的排列只有 “2 奇质数 2”。
分析到这里不能发现,长度为 的序列怎么搞都不合法,因为只能出现 “2 奇质数 2 奇质数” 这样的的排列,加一起是偶数,不合法。
所以长度为 的序列没有合法序列,那么长度是 的序列也自然不存在合法序列。
所以我们只需要考虑长度 的情况,是不是简单许多。。。
T5
给定一棵 个节点的树,顶点编号为 ,你需要给每个顶点设置一个标号 满足:
- ( 树上相邻)
求方案数。
可以考虑暴力的 ,设 表示当前填了 的标号,其中 填在点 , 填在点 ,填过的点的集合是 的方案数。
枚举标号 将要填的位置,记作 ,设新集合是 ,那么有如下转移:
直接暴力的 无疑会超时,考虑优化,采用排除无用状态的方式。
考虑这样的问题,如果 的标号都填完了,我们能否确定当前填的方案是否合法呢?
显然可以,对于 而言,满足 并且 树上相邻的无非在 内,由于我们按照标号从小到大的顺序填,若填到 ,对于 填在的位置(记作 )来讲,与 相邻的点还有没填的,即使后面填上也不可能合法,所以我们得到如下结论:
填完 ,与 位置相邻的必须全部填上。
加上这个剪枝以及记忆化搜索,就可以 A 了。
为什么?
首先,每个点的度数一定不超过 ,超过 显然无解,接着,我们将 中的 点删除,最多得到 棵树,每棵树要么全部被填,要么全部不被填。如果出现落单的,在后面的填写中也不可能被填,所以合法的状态最多有 种,设树的个数是 。
那么时间复杂度是
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效