东方博宜OJ 1529:基因锁 ← KMP算法 + 区间点覆盖 + 贪心
【题目来源】
【题目描述】
……
人类的基因序列(英文缩写为 DNA)是一个由字母 'A','C','G','T' 组成的字符串,肥胖基因是其中的一个子串(子串为原串中一段连续的字符)。
外星人对小 X 的基因手术过程是这样的:先找出所有的肥胖基因,并将它们用基因墨水染成红色,然后将某些字符加上基因锁,一把基因锁只能锁住一个字符,一个肥胖基因只要有一个字符加上了基因锁,则这个肥胖基因就不再起作用。
现在要你计算有多少个字符被基因墨水染成了红色?最少需要多少把基因锁才能将所有的肥胖基因锁住?
【输入格式】
第一行包含两个用空格隔开的正整数 L1,L2,表示小 X 基因的长度和肥胖基因的长度。
第二行为一个长度为 L1 的字符串,表示小 X 的基因。
第三行为一个长度为 L2 的字符串,表示肥胖基因。数据保证 L1>L2。
【输出格式】
输出一行包含两个整数,表示被基因墨水染成了红色的字符个数和所需的基因锁数量,两数之间严格用一个空格隔开。
【输入样例】
16 3
CGCGCATCGCATTAGG
CGC
【输出样例】
8 2
【数据范围】
10% 的数据,肥胖基因为单个字符;
40% 的数据,所有的肥胖基因互相不重叠;
100% 的数据,基因长度不超过 10^6,肥胖基因长度不超过 10,保证字符只会出现 'A','C','G',T'。
【算法分析】
● 这道题两个问题,分开解决:
(1)染红字符数:所有被匹配到的模式串覆盖的不同位置总数。
(2)最少基因锁:经典区间点覆盖问题,用最少的点戳中所有区间(贪心)。
● 代码里用的贪心策略是“每次在当前区间的最右端放锁”。为什么?因为靠右放,能最大概率覆盖后面可能重叠的区间,从而用最少数量的锁覆盖所有区间,保证得到最优解。
例如,对于字符串 ACBCBCBC 与模式串 CBC,匹配得到三个首尾相接的区间 [1,3]、[3,5]、[5,7] ,采用 “在当前区间最右端放锁” 的贪心策略,是因为将锁放在区间右端点能尽可能覆盖后续与之重叠的区间:第一个区间 [1,3],在右端点 3 放锁,可同时覆盖自身与下一个区间 [3,5],无需额外加锁;待遍历到未被覆盖的第三个区间 [5,7] 时,再在其右端点 7 放锁即可覆盖全部区间,仅用2把锁就完成全部锁定。若选择在区间左侧或中间位置放锁,会无法覆盖后续相邻区间,导致需要更多锁,而靠右放锁能最大程度利用区间重叠,用最少数量的锁覆盖所有区间,这也是该贪心策略能得到最优解的关键原因。
【算法代码】
【参考文献】

浙公网安备 33010602011771号