洛谷 P1090 [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G python解析

P1090 [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G

时间:2023.10.4
题目地址:合并果子

题目分析

了解题意后,要想取最优的,贪心策略就是每次取两个最小堆进行合并 ( 注意:合并后的堆也要考虑进去, 就是说合并后在考虑最小堆的时候也要考虑。 ) 。
n n n 堆的话只需排 n − 1 n-1 n1 次就行了,题目已经告诉你了。
我想到的就是两种思路:

  1. 先将数组排序,然后将前两个最小堆合并后,在删掉一个堆,然后再对这个数组进行排序,最后只剩一堆后输出。如下图分析。
    看了数据量很可能超时,果然超时了,只有30分。
    分析
    超时代码

  2. 首先,还是对输入的数组进行排序,然后在开一个队列,放合并后的堆,通过比大小来判断堆的合并,保证了每次取的都是最小的两个,并且相较于上个方法省去了删堆和排序的时间。
    新开的队列存的堆也是有序的,这应该没什么问题。然后就通过索引来跟进就行了,注意越界问题。
    不出意外,都过了。
    满分代码

代码

  1. 30分超时代码
n = int(input())

nums = [int(i) for i in input().split()]
nums = sorted(nums) + [0]*(30001-n)

total = 0
while True:
    j = 0
    # 只剩一堆后输出
    if j+1 >= n:
        break
    else:
    	# 合并
        nums[j] = nums[j] + nums[j+1]
        # 删堆
        for k in range(j+1, n):
            nums[k] = nums[k+1]
        total += nums[j]
        n -= 1
    # 排序
    for l in range(j, n-1):
        if nums[l] > nums[l+1]:
            nums[l], nums[l+1] = nums[l+1], nums[l]

print(total)
  1. 满分代码
n = int(input())

nums = [int(i) for i in input().split()]
nums.sort()
# 存放合并堆的队列
nums_2 = [float('inf') for _ in range(n)]
# 目标
total = 0
# 判断此时最小的两个堆的指向
i = 0
j = 0
# 趟次
k = 1
# 存放每次的合并堆的索引/指针
index = 0
while k < n:
	# 防止越界
    if i > n-1: # 此时nums没有堆了,取完了
        temp = nums_2[j]
        j += 1
    else:
        if nums[i] < nums_2[j]: # 每次取最小的
            temp = nums[i]
            i += 1
        else:
            temp = nums_2[j]
            j += 1
    # 防止越界
    if i > n-1: # 此时nums没有堆了,取完了
        temp += nums_2[j]
        j += 1
    else:
        if nums[i] < nums_2[j]: # 每次取最小的
            temp += nums[i]
            i += 1
        else:
            temp += nums_2[j]
            j += 1
    nums_2[index] = temp
    total += temp
    k += 1
    index += 1

print(total)

思考

为什么只有可能是 i i i 越界,而 j j j 不会越界呢?读者可以自己思考。

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值