算法--解决熄灯问题

复制代码
import numpy as np

# 初始化一个空列表,用于存储用户输入的每一行灯状态数据
line = []

# 通过循环让用户逐行输入灯的初始状态数据
for i in range(5):
    # 获取用户输入的第i行数据,并去除输入字符串两端可能存在的空白字符(如空格、换行等)
    line_input = input("请输入第" + str(i) + "行:").strip()
    # 将输入的字符串形式的数据转换为整数列表,例如 "101010" 会转换为 [1, 0, 1, 0, 1, 0],然后添加到line列表中
    line.append(list(map(int, line_input)))

# 将存储了用户输入的5行灯状态数据的列表转换为二维的numpy数组,方便后续进行矩阵操作
puzzle = np.array(line)

# 创建一个形状为(1, 6)的全零二维数组,数据类型为整数,用于在行方向上添加到puzzle数组的开头,作为额外的边界行(可能是为了符合特定算法逻辑对边界的处理需求)
zero_row = np.zeros((1, 6), dtype=int)
# 使用np.vstack函数将zero_row数组和puzzle数组按垂直方向(行方向)堆叠在一起,也就是在puzzle数组的开头添加了一行全零数据
puzzle = np.vstack((zero_row, puzzle))

# 创建一个形状为(6, 1)的全零二维数组,数据类型为整数,用于在列方向上添加到puzzle数组的两侧,作为额外的边界列(同样可能是为了满足后续算法对边界情况的处理)
zero_col = np.zeros((6, 1), dtype=int)
# 使用np.hstack函数将两个zero_col数组和中间的puzzle数组按水平方向(列方向)堆叠在一起,即在puzzle数组的最左边和最右边各添加了一列全零数据
puzzle = np.hstack((zero_col, puzzle, zero_col))

# 创建一个形状为(6, 8)的全零二维数组,数据类型为整数,用于记录每个位置的“按下”操作情况,初始时所有位置都为未按下(值为0)
press = np.zeros((6, 8), dtype=int)


def guess():
    """
    guess函数用于根据当前的灯状态(puzzle数组)和按下操作情况(press数组),判断当前按下操作是否能使得所有灯熄灭(满足特定条件)。
    具体是按照一定的规则更新press数组中对应位置的值,并检查最后一行灯的状态是否符合预期(这里推测是熄灭状态)。
    """
    # 遍历除了添加的边界行之外的“有效”行(索引从1到5,实际对应原来输入的5行数据所在的行范围)
    for r in range(1, 5):
        # 遍历除了添加的边界列之外的“有效”列(索引从1到7,实际对应原来输入的6列数据所在的列范围)
        for c in range(1, 7):
            # 根据周围灯的状态以及当前位置的按下操作情况,按照特定规则(可能是点灯游戏里的规则,通过异或操作实现状态变化逻辑)计算下一行对应位置的按下操作值,这里取余2实现类似异或的效果,确保结果为0或1
            press[r + 1][c] = (puzzle[r][c] + press[r][c] +
                               press[r - 1][c] + press[r][c - 1] +
                               press[r][c + 1]) % 2
    # 检查最后一行(索引为5,对应添加边界后的实际最后一行)灯的状态是否符合预期(根据某种规则判断是否全部熄灭等情况)
    for c in range(1, 7):
        if (press[5][c - 1] + press[5][c] + press[5][c + 1] + press[4][c]) % 2!= puzzle[5][c]:
            return 0
    return 1


def enumeration():
    """
    enumeration函数使用穷举法来尝试找到一种按下操作组合(通过修改press数组的值),使得所有灯最终熄灭(满足guess函数里判断的条件)。
    它通过不断改变press数组中第一个“有效”位置(press[1][1])的值,并按照一定规则逐步调整其他位置的值,反复调用guess函数进行判断,直到找到满足条件的组合为止。
    """
    # 只要guess函数返回0,说明当前按下操作组合不能使得所有灯熄灭,就继续循环尝试不同的按下操作组合
    while guess() == 0:
        # 先尝试改变press数组中第一个“有效”位置(press[1][1])的值,将其加1(因为初始值为0,这里开始尝试不同的按下情况)
        press[1][1] += 1
        c = 1
        # 当press[1][c]的值大于1时(由于这里只有0和1两种状态表示是否按下,大于1不符合要求),进行如下处理
        while press[1][c] > 1:
            # 将当前位置的值重置为0,表示不按下
            press[1][c] = 0
            c += 1
            # 只有当列索引小于8(在有效列范围内)时,才对下一个位置的值加1,继续尝试下一种按下情况
            if c < 8:
                press[1][c] += 1


# 调用enumeration函数开始通过穷举法寻找满足条件的按下操作组合
enumeration()

# 输出灯的初始状态,这里通过切片操作去除了之前添加的边界行和边界列,只显示用户最初输入的5行6列的灯初始状态数据
print("灯的初始状态:\n", puzzle[1:6, 1:7])
# 输出最终找到的满足条件的按下操作组合情况,同样通过切片操作去除边界部分,显示对应“有效”区域内的按下操作情况
print("按下结果为:\n", press[1:6, 1:7])
输出结果:
相关推荐
不想编程小谭15 分钟前
力扣LeetCode: 2506 统计相似字符串对的数目
c++·算法·leetcode
水蓝烟雨32 分钟前
[HOT 100] 2187. 完成旅途的最少时间
算法·hot 100
豌豆花下猫37 分钟前
Python 潮流周刊#90:uv 一周岁了,优缺点分析(摘要)
后端·python·ai
橘猫云计算机设计1 小时前
基于SSM的《计算机网络》题库管理系统(源码+lw+部署文档+讲解),源码可白嫖!
java·数据库·spring boot·后端·python·计算机网络·毕设
小伍_Five1 小时前
从0开始:OpenCV入门教程【图像处理基础】
图像处理·python·opencv
m0_748245341 小时前
python——Django 框架
开发语言·python·django
菜鸟一枚在这2 小时前
深度解析建造者模式:复杂对象构建的优雅之道
java·开发语言·算法
java1234_小锋2 小时前
一周学会Flask3 Python Web开发-客户端状态信息Cookie以及加密
前端·python·flask·flask3
gyeolhada2 小时前
2025蓝桥杯JAVA编程题练习Day5
java·数据结构·算法·蓝桥杯
阿巴~阿巴~2 小时前
多源 BFS 算法详解:从原理到实现,高效解决多源最短路问题
开发语言·数据结构·c++·算法·宽度优先