1855 愤怒的奶牛(思维题、枚举)

1. 问题描述:

奶牛贝茜设计了一款她认为必火的游戏:愤怒的奶牛。游戏设定(她坚信这是她的原创)是玩家用一个弹弓将一头奶牛射向一个数轴,数轴的不同位置上分布着一些干草捆。奶牛以足够的力量砸向某个干草捆,并使得该干草捆发生爆炸,爆炸可能会不断引起连锁反应,导致更多的干草捆发生爆炸。目标是用一头奶牛引起的连锁反应引爆尽可能多的干草捆。共有 N 个干草捆位于数轴中的不同整数位置,其坐标依次为 x1,x2,…,xN。如果将奶牛射向位于位置 x 的干草捆,则该干草捆发生爆炸,爆炸半径为 1,爆炸将吞噬 1 单位距离内的所有干草捆。然后这些干草捆(全部同时)发生爆炸,每个干草捆的爆炸半径为 2。二次爆炸中吞噬的所有尚未爆炸的干草捆也(全部同时)发生爆炸,爆炸半径为 3。也就是说,在 t 时刻爆炸的干草捆的爆炸半径为 t,其爆炸波及的干草捆在 t + 1 时刻也会爆炸,爆炸半径为 t + 1,以此类推。请确定,通过合理选择奶牛射向的干草捆,能够引爆的干草捆最大数量。

输入格式

第一行包含整数 N。接下来 N 行包含 x1,…,xN。

输出格式

输出能够引爆的干草捆的最大数量。

数据范围

1 ≤ N ≤ 100,
0 ≤ xi ≤ 10 ^ 9

输入样例:

6
8
5
6
13
3
4

输出样例:

5

样例解释
将奶牛射向位于位置 5 的干草捆,产生半径为 1 的爆炸。爆炸吞噬位置 4 和 6 处的干草捆,引发半径为 2 的二次爆炸。二次爆炸吞噬位置 3 和 8 处的干草捆,引发半径为 3 的三次爆炸。位置 13 的干草捆无法被引爆。
来源:https://www.acwing.com/problem/content/description/1857/

2. 思路分析:

这道题目思维上还是有一定难度的,首先我们需要考虑如何将题目做出来然后再考虑如何进行优化,最容易想到的是暴力枚举,搜索出能够引爆的最大干草捆的数量但是这样做的时间复杂度比较高而且代码写起来比较麻烦,我们需要挖掘一下题目的性质才能够进行优化,首先需要分析干草捆爆炸的过程,可以发现从一个干草捆位置开始引爆那么会引爆周围半径内的干草捆,也即产生连锁反应,可以发现干草捆爆炸的过程有一个特点是:从当前某个位置开始引爆那么周围的爆炸范围都是连续的,有了这个特点之后就比较好处理了,我们要求解能够引爆的最大干草捆的数量那么需要求解的就是爆炸范围的左右边界,所以首先第一点肯定是枚举,枚举引爆当前位置i的的干草捆,从位置i出发找到产生连锁反应之后的左边界和右边界,这样就可以计算出当前可以引爆多少个干草捆用来更新答案。(因为引爆的范围是一个直径所以找左右端点的时候要想范围越大那么需要尽量往左边/右边进行扩展直到不能够扩展就停止了)。

3. 代码如下:

class Solution:
    def process(self):
        n = int(input())
        q = list()
        for i in range(n):
            q.append(int(input()))
        # 按照坐标的位置从小到大排序
        q.sort()
        # 插入哨兵这样可以不用考虑边界情况, 这两个哨兵一定不会被引爆, 左右哨兵比最小/大位置稍微x小/大一点就可以
        INF = 2 * 10 ** 9
        # 插入两个哨兵
        q.insert(0, -INF)
        q.append(INF)
        res = 0
        # 最外层循环表示枚举引爆当前的第i个位置的干草捆
        for i in range(1, n + 1):
            # l, r表示当前引爆的半径
            l = r = 1
            # a, b表示引爆的左右位置
            a = b = i
            # 引爆了左边位置的干草捆, 那么产生了连锁反应这个时候需要找到能够引爆的最左边的那个位置
            while q[a] - q[a - 1] <= l:
                k = a - 1
                # 找到当前l范围内最左边的干草捆的位置
                while q[a] - q[k - 1] <= l: k -= 1
                a = k
                # 扩大引爆半径
                l += 1
            # 引爆了右边位置的干草捆, 那么产生了连锁反应这个时候需要找到能够引爆的最右边的那个位置
            while q[b + 1] - q[b] <= r:
                k = b + 1
                while q[k + 1] - q[b] <= r: k += 1
                b = k
                r += 1
            # 左右区间中干草捆的数量就是当前引爆位置i之后能够引爆的最大干草捆的数量
            res = max(res, b - a + 1)
        return res


if __name__ == '__main__':
    print(Solution().process())
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值