当前位置: 首页 > article >正文

算法篇:贪心算法

题目一:均分纸牌

有n堆纸牌,编号分别为 1,2,…,n1,2,…,n。每堆上有若干张,但纸牌总数必为nn的倍数。可以在任一堆上取若干张纸牌,然后移动。

移牌规则为:在编号为11的堆上取的纸牌,只能移到编号为 22 的堆上;在编号为 nn 的堆上取的纸牌,只能移到编号为n−1n−1的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。

现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。

例如:

n=4堆纸牌数分别为:  ① 9 ② 8 ③ 17 ④ 6

移动3次可达到目的:

从 ③ 取4张牌放到④(9 8 13 10)->从③取3张牌放到 ②(9 11 10 10)-> 从②取1张牌放到①(10 10 10 10)。

cards = [9,8,17,6,9,11]

def min_moves_to_balance():
    n = len(cards)
    target = sum(cards) // n  # 每堆纸牌应达到的目标数量
    moves = 0  # 记录移动次数
    queue = [(i, cards[i] - target) for i in range(n) if cards[i] != target]  # 创建一个队列来存储不平衡的堆及其差值
    print(queue)
    while queue:
        # 从队列中取出一个不平衡的堆
        i, diff = queue.pop(0)
        # 根据堆的编号来决定如何移动纸牌
        if i == 0:
            # 如果是第一堆,并且纸牌多于目标数量,则只能向第二堆移动
            if diff > 0:
                move_amount = min(diff, target - cards[1])
                cards[0] -= move_amount
                cards[1] += move_amount
                moves += 1  # 注意:这里应该按移动的次数累加,而不是按移动的量
                # 更新第二堆的状态,如果第二堆仍然不平衡,则重新加入队列
                if cards[1] != target:
                    queue.append((1, cards[1] - target))
        elif i == n - 1:
            # 如果是最后一堆,并且纸牌多于目标数量,则只能向倒数第二堆移动
            if diff > 0:
                move_amount = min(diff, target - cards[n - 2])
                cards[n - 1] -= move_amount
                cards[n - 2] += move_amount
                moves += 1
                # 更新倒数第二堆的状态,如果仍然不平衡,则重新加入队列
                if cards[n - 2] != target:
                    queue.append((n - 2, cards[n - 2] - target))
        else:
            # 如果是中间的堆,则可以向左边或右边移动纸牌
            if diff > 0:
                # 尝试向右边移动
                move_right = min(diff, target - cards[i + 1])
                if move_right > 0:
                    cards[i] -= move_right
                    cards[i + 1] += move_right
                    moves += 1
                    # 更新右边堆的状态,如果仍然不平衡,则重新加入队列
                    if cards[i + 1] != target:
                        queue.append((i + 1, cards[i + 1] - target))
                # 如果右边堆已满或无法再接收更多纸牌,则尝试向左边移动
                move_left = diff - move_right
                if move_left > 0:
                    cards[i] -= move_left
                    cards[i - 1] += move_left
                    moves += 1
                    # 更新左边堆的状态,如果仍然不平衡,则重新加入队列
                    if cards[i - 1] != target:
                        queue.append((i - 1, cards[i - 1] - target))
            elif diff < 0:
                # 如果纸牌少于目标数量,则尝试从左边或右边接收纸牌
                # 注意:这里我们不需要显式地处理从左边或右边接收纸牌的情况,
                # 因为在之前的迭代中,相邻的堆已经(或将会)尝试向我们当前处理的堆移动纸牌。
                # 我们只需要确保在之前的迭代中,相邻堆有多余的纸牌可以移动给我们。
                # 因此,这里的diff < 0情况实际上会被之前的迭代处理掉(通过相邻堆的diff > 0情况)。
                pass  # 不需要执行任何操作,因为相邻堆会负责平衡我们

    # 由于我们按移动的次数累加,而不是按移动的量,所以moves直接就是最少的移动次数
    return moves


# 示例测试

ret = min_moves_to_balance() # 输出应为符合题目要求的最少移动次数

print(ret)

# 为了验证结果,可以打印最终平衡的纸牌堆(理论上应该是[10, 10, 10, 10])
print(cards)


http://www.kler.cn/a/412121.html

相关文章:

  • Linux服务器生成SSH 密钥对与 GitLab 仓库进行交互
  • 2024 APMCM亚太数学建模C题 - 宠物行业及相关产业的发展分析和策略(详细解题思路)
  • Bug Fix 20241122:缺少lib文件错误
  • 概率论中交并集的公式
  • 微信小程序2-地图显示和地图标记
  • 极狐GitLab 17.6 正式发布几十项与 DevSecOps 相关的功能【一】
  • vue3 属性透传
  • Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No “exports“ main defined
  • 本地 PHP 和 Java 开发环境 Docker 化与配置开机自启
  • 详解Qt 中使用虚拟键盘(软键盘qtvirtualkeyboard)
  • 【面试分享】主流编程语言的内存回收机制及其优缺点
  • fastjson不出网打法—BCEL链
  • Leetcode 290 word Pattern
  • 【Qt】Qt 在main.cpp中使用tr()函数报错
  • 【设计模式】【结构型模式(Structural Patterns)】之装饰模式(Decorator Pattern)
  • WordPress文章目录插件,LuckyWP Table of Contents自动生成文章插件
  • vue图片导入的几种方式及优劣对比
  • 通用网络安全设备之【防火墙】
  • YOLOX的正负样本分配问题
  • 如何使用Postman优雅地进行接口自动加密与解密
  • Rust学习(十):计算机科学简述
  • 网络基础二
  • 掌握 Spring 事务管理:深入理解 @Transactional 注解(二)
  • HTTP 缓存技术
  • Cannot find a valid baseurl for repo: centos-sclo-rh/x86_64
  • Linux的前台进程和后台进程