1672 疯狂的科学家(贪心)

本文介绍了一个关于字符串操作的问题,FarmerJohn需要通过最少的奶牛品种转换来调整农场奶牛的品种序列。通过分析,提出了一种贪心策略,将操作转换为01串表示,只需计算连续1的区间数即为答案。关键在于理解翻转操作的对称性,寻找最优的不相交区间划分。
摘要由CSDN通过智能技术生成

1. 问题描述:

Farmer John 的远房亲戚 Ben 是一个疯狂的科学家。通常这会在家庭聚会时造成不小的摩擦,但这偶尔也会带来些好处,尤其是当 Farmer John 发现他正面对一些有关他的奶牛们的独特而不寻常的问题时。Farmer John 当前正面对一个有关她的奶牛们的独特而不寻常的问题。他最近订购了 N 头奶牛,包含两种不同品种:荷斯坦牛和更赛牛。他在订单中用一个长为 N 的字符串来指定奶牛,其中的字符为 H(表示荷斯坦牛)或 G(表示更赛牛)。不幸的是,当这些奶牛到达他的农场,他给她们排队时,她们的品种组成的字符串与原先的不同。我们将这两个字符串称为 A 和 B,其中 A 是 Farmer John 原先想要的品种字符组成的字符串,B 是他的奶牛们到达时组成的字符串。Farmer John 并没有简单地检查重新排列 B 中的奶牛是否能得到 A,而是请他的远房亲戚 Ben 利用他的科学才华来解决这一问题。经过数月的研究,Ben 发明了一台不同寻常的机器:奶牛品种转换机3000,能够选择任意奶牛组成的子串并反转她们的品种:在这个子串中的所有 H 变为 G,所有 G 变为 H。Farmer John 想要求出将他当前的序列 B 变为他本来订购时想要的 A 需要使用这台机器的最小次数。然而,Ben 的疯狂的科学家技能并不会处理开发奇异机器以外的事,所以你需要帮助 Farmer John 解决这个计算难题。

输入格式

输入的第一行包含 N,以下两行包含字符串 A 和 B。每个字符串均包含 N 个字符,字符均为 H 和 G 之一。

输出格式

输出将 B 变为 A 需要使用机器的最小次数。

数据范围

1 ≤ N ≤ 1000

输入样例:

7
GHHHGHH
HHGGGHH

输出样例:

2
样例解释
首先,FJ 可以仅改变第一个字符组成的子串,将 B 变为 GHGGGHH。然后,他可以改变由第三和第四个字符组成的子串,得到 A。当然,还存在其他有效的执行两次操作的方案。
来源:https://www.acwing.com/problem/content/1674/

2. 思路分析:

分析题目可以知道已知两个字符串A和B,我们需要将B通过翻转其中的一段操作若干次使得最终变为A,求解最小需要翻转的次数,如果直接做可以发现方案数目非常多,并且翻转的结果只取决于对应字母的操作次数,不取决于翻转顺序那么这样方案数目就非常多,直接做是不好做的,对于这种直接求解方案数目非常多并且没有规律的题目一般是找一下最优解有什么性质,如下图所示我们可以将大圆看成是所有操作方案的集合,中间的小圆可以看成是满足某种性质的操作方案的集合,我们需要挖掘一下小圆对应的集合是否存在某种性质(当找到这种性质之后那么就比较好解决了):

可以发现当对某个字母操作2次等于没有操作,所以对于任意两个相交或者包含的区间我们都可以将其等价替换为两个不相交的区间,替换完之后结果不会变得更差,而且最多有两步操作,所以可以发现任给一组最优解只要存在两个相交的区间我们都可以将它们替换为不相交的长度更短的区间,最终所有的区间都是不相交的而且结果不会变得更差所以上图中小圆可以看成是不相交的操作方案的集合,所以任给一个最优解都可以转换为小圆中等价的方案这样结果不会变差,这样我们就证明了小圆中至少存在一个最优解是全局最优解,所以我们可以在小圆中至少找到一个最优解为全局最优解。

这样我们就找到了一种性质,全局最优解一定可以转化为若干个不相交的区间,这样就比较好处理了,所以当前位置的字符要么被覆盖0次,要么被覆盖1次,可以发现如果A[i] = B[i],说明只能够被覆盖0次,当A[i] != B[i]只能被覆盖一次,所以每一个位置字符的覆盖次数是唯一确定的,这样我们就可以将其转换为对应的01串,我们只需要求解出对应连续的1的区间数目那么就是答案,在枚举的时候发现当前的A[i] != B[i]说明当前字母被覆盖一次这个时候使用双指针找到连续一段1的位置,更新答案即可。

3. 代码如下:

class Solution:
    # 贪心
    def process(self):
        n = int(input())
        a, b = input(), input()
        i = 0
        res = 0
        while i < n:
            # 说明当前只能够被覆盖一次
            if a[i] != b[i]:
                j = i + 1
                # 双指针找到连续的1的一段
                while j < n and a[j] != b[j]: j += 1
                # 找到了一段连续的1, 区间数目加1
                res += 1
                # 修改当前枚举位置i
                i = j
            i += 1
        return res


if __name__ == "__main__":
    print(Solution().process())
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值