贴吧趣味问题——一线连24点【编程穷举证明无解】

24点 - DFS Time Limit:1000ms          Memory Limit: 65535KB 在Jason生活的星球上,算术学期末总是考同样的题目:抽四张扑克牌,在1秒内通过四则运算让其结果为24。 但是Jason的算术太拙了,总是没办法在1秒内得到正确答案。期末考试就快要到了,但正直的Jason不想靠命运力神抽4张6来通过考试。 你能为Jason设计一个24点的算法,好让他不挂 阅读详情
AI摘要

探讨使用回溯法解决连点游戏问题,通过递归探索所有可能路径,优化算法减少无效搜索,最终证明特定布局下问题无解。

逛贴吧的时候遇到了一个趣味问题
在这里插入图片描述
这里我再重复一遍问题
如下图所示,不过黑点,把所有白色圆圈用一条线连起来,不能重复,不能斜着连(更不能像上图那样穿墙传送)
在这里插入图片描述
把上图用矩阵文本表示出来如下(0代表黑点,即不能连的点):

1, 0, 1, 1, 1
1, 1, 1, 1, 1
1, 1, 1, 1, 1
1, 1, 1, 1, 1
1, 1, 1, 1, 1

1-思路分析

倘若问题有解,即能够一条线连接所有点
那一条线必然有两个端点,由于左上角的1只有一个相邻点可以连接,必然为一个端点(非端点必须是起码有两个可以连接的相邻点的)
不妨以左上角的1为起点去探索,如果递归尝试所有方向后均不能一条线连接所有点,则说明该问题无解

2-递归实现代码(回溯法)

这里的代码思路和我之前的博客:【教程】python递归三部曲(基于turtle实现可视化)-三、迷宫探索基本是一样的
感兴趣的话,也可以对比着看看
一条线连的探索过程为:
从起点(左上角的1)出发,分别按顺序往上下左右四个方向去探索(即连接上下左右的可以连接的相邻点),
在这一过程中递归地对连接后的相邻点进行进一步四周的探索(即将该相邻点当做新的起点去执行上一步骤,直至探索完成或失败,才开始下一个方向的探索)
探索的具体过程可以分下面几种情况:

  1. 该点不可连接(黑点或已经连接过的点)或超出边界,告诉上一步这一步探索失败
  2. 没有可以连接的点了,但a) 连完了所有点,探索完成,告诉上一步这一步探索成功 ,b)没连完所有点,探索失败,然后告诉上一步这一步探索是失败的
  3. 向某个方向的探索得出的结论是成功的,那么探索完成,不在探索,并且告诉上一步探索这一方向是能够探索成功的
  4. 向某个方向的探索得出的结论是失败的,那么换一个方向进行探索

结合以上分析,可以写出探索的递归方法searchNext,全部代码如下

problem_board = [
    [1, 0, 1, 1, 1],
    [1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1]
]


def check_all_linked(board):
    for row in board:
        for v in row:
            if v == 1:
                return False

    return True


def search_next(board, ci, ri, v):
    # 1. 该点不可连接(黑点或已经连接过的点)或超出边界,告诉上一步这一步探索失败
    if not (0 <= ci < len(board[0]) and 0 <= ri < len(board)):
        # 超出边界
        return False
    if board[ri][ci] != 1:
        # 黑点或已经连接过的点
        return False

    board[ri][ci] = v + 1

    direction = [
        (1, 0),
        (0, -1),
        (-1, 0),
        (0, 1),
    ]

    for d in direction:
        dc, dr = d

        found = search_next(board, ci + dc, ri + dr, v+1)
        if found:
            # 3. 向某个方向的探索得出的结论是成功的,那么探索完成,不在探索,并且告诉上一步探索这一方向是能够探索成功的
            return True
        else:
            # 4. 向某个方向的探索得出的结论是失败的,那么换一个方向进行探索
            pass

    # 2. 没有可以连接的点了
    # a) 连完了所有点, 探索完成,告诉上一步这一步探索成功
    if check_all_linked(board):
        return True

    # b)没连完所有点**,探索失败,然后告诉上一步这一步探索是失败的
    board[ri][ci] = 1
    return False

r = search_next(problem_board, 0, 0, 1)
print(r)

输出为

False

3-turtle实现可视化

import turtle

# 建立窗体
SCR = turtle.Screen()

SCR.setup(800, 800)  # 设置窗体大小

radius = 40
distance = 120


problem_board = [
    [1, 0, 1, 1, 1],
    [1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1]
]

simple_problem_board_0 = [
    [1, 0, 1, 1],
    [1, 1, 1, 1],
    [1, 1, 1, 1],
    [1, 1, 1, 1],
]

simple_problem_board_1 = [
    [1, 0, 1],
    [1, 1, 1],
    [1, 1, 1]
]

dot_t = turtle.Turtle()
dot_t.hideturtle()
dot_t.speed(0)
dot_t.width(2)

link_t = turtle.Turtle()
link_t.hideturtle()
link_t.pensize(5)
link_t.penup()
link_t.speed(0)
link_t.color("blue")


def draw_white_dot(x, y):
    dot_t.penup()
    dot_t.goto(x, y - radius)
    dot_t.setheading(0)
    dot_t.pendown()
    dot_t.circle(radius)


def draw_black_dot(x, y):
    dot_t.penup()
    dot_t.goto(x, y - radius)
    dot_t.setheading(0)
    dot_t.pendown()
    dot_t.begin_fill()
    dot_t.circle(radius)
    dot_t.end_fill()


def draw_board(board):
    r = len(board)
    c = len(board[0])

    width = (r-1) * distance
    height = (c-1) * distance

    sx = - width // 2
    sy = height // 2

    link_t.goto(sx, sy)
    link_t.pendown()

    for ri in range(r):
        for ci in range(c):
            xi = sx + ci * distance
            yi = sy - ri * distance
            v = board[ri][ci]

            if v == 0:
                draw_black_dot(xi, yi)
            else:
                draw_white_dot(xi, yi)


def check_all_linked(board):
    for row in board:
        for v in row:
            if v == 1:
                return False

    return True


def search_next(board, ci, ri, v, di):
    # 1. 该点不可连接(黑点或已经连接过的点)或超出边界,告诉上一步这一步探索失败
    if not (0 <= ci < len(board[0]) and 0 <= ri < len(board)):
        # 超出边界
        return False
    if board[ri][ci] != 1:
        # 黑点或已经连接过的点
        return False

    if v > 1:
        link_t.setheading(di * 90)
        link_t.forward(distance)

    board[ri][ci] = v + 1

    # 必须按照右上左下的顺序,与画笔方向才能一致
    direction = [
        (1, 0),
        (0, -1),
        (-1, 0),
        (0, 1),
    ]

    for i, d in enumerate(direction):
        dc, dr = d

        found = search_next(board, ci + dc, ri + dr, v+1, i)
        if found:
            # 3. 向某个方向的探索得出的结论是成功的,那么探索完成,不在探索,并且告诉上一步探索这一方向是能够探索成功的
            return True
        else:
            # 4. 向某个方向的探索得出的结论是失败的,那么换一个方向进行探索
            pass

    # 2. 没有可以连接的点了
    # a) 连完了所有点, 探索完成,告诉上一步这一步探索成功
    if check_all_linked(board):
        return True

    # b)没连完所有点**,探索失败,然后告诉上一步这一步探索是失败的
    board[ri][ci] = 1
    for _ in range(2):
        link_t.undo()
    return False


# draw_board(simple_problem_board_1)
# search_next(simple_problem_board_1, 0, 0, 1, 0)

# draw_board(simple_problem_board_0)
# search_next(simple_problem_board_0, 0, 0, 1, 0)

draw_board(problem_board)
search_next(problem_board, 0, 0, 1, 0)
turtle.done()

问题是回溯法的时间复杂度过高,所以导致这个绘制动画要耗时很久
这里在第四部做个优化

4-可视化动画优化

在search_next方法中发现圆点已经被连线分成两个不相连的部分的时候,就已经可以说明当前的连线方式有问题,探索失败并通知上一步
故这里将第三部分的代码添加上advanced_search_next方法,待添加的代码如下

def check_board_separated(board):
    check_board = [row[:] for row in board]
    sr = -1
    sc = -1
    for ri in range(len(check_board)):
        for ci in range(len(check_board[0])):
            if check_board[ri][ci] == 1:
                sr = ri
                sc = ci
                break
        if sr >= 0:
            break

    if sr < 0:
        return False

    direction = [
        (1, 0),
        (0, -1),
        (-1, 0),
        (0, 1),
    ]

    check_board[sr][sc] = 2
    to_explore = [(sc, sr)]
    while len(to_explore) > 0:
        new_to_explore = []
        for item in to_explore:
            ci, ri = item
            for i, d in enumerate(direction):
                dc, dr = d
                nc, nr = dc + ci, dr + ri
                if (0 <= nc < len(board[0]) and 0 <= nr < len(board)) and check_board[nr][nc] == 1:
                    check_board[nr][nc] = 2
                    new_to_explore.append((nc, nr))

        to_explore = new_to_explore

    for ri in range(len(check_board)):
        for ci in range(len(check_board[0])):
            if check_board[ri][ci] == 1:
                return True

    return False


def advanced_search_next(board, ci, ri, v, di):
    # 1. 该点不可连接(黑点或已经连接过的点)或超出边界,告诉上一步这一步探索失败
    if not (0 <= ci < len(board[0]) and 0 <= ri < len(board)):
        # 超出边界
        return False
    if board[ri][ci] != 1:
        # 黑点或已经连接过的点
        return False

    if v > 1:
        link_t.setheading(di * 90)
        link_t.forward(distance)

    board[ri][ci] = v + 1

    if check_board_separated(board):
        board[ri][ci] = 1
        if v > 1:
            link_t.undo()
            link_t.undo()

        return False

    # 必须按照右上左下的顺序,与画笔方向才能一致
    direction = [
        (1, 0),
        (0, -1),
        (-1, 0),
        (0, 1),
    ]

    for i, d in enumerate(direction):
        dc, dr = d

        found = advanced_search_next(board, ci + dc, ri + dr, v+1, i)
        if found:
            # 3. 向某个方向的探索得出的结论是成功的,那么探索完成,不在探索,并且告诉上一步探索这一方向是能够探索成功的
            return True
        else:
            # 4. 向某个方向的探索得出的结论是失败的,那么换一个方向进行探索
            pass

    # 2. 没有可以连接的点了
    # a) 连完了所有点, 探索完成,告诉上一步这一步探索成功
    if check_all_linked(board):
        return True

    # b)没连完所有点**,探索失败,然后告诉上一步这一步探索是失败的
    board[ri][ci] = 1
    for _ in range(2):
        link_t.undo()
    return False

最后调用时
把search_next改为advanced_search_next调用就好

5 - 通过逻辑简单证明

实际上,有更简单的方法证明该问题是无解的

  1. 先把左上角的圆圈标为A
  2. A的上下左右相邻的可以连接的圆圈标为B
  3. B的上下左右相邻的可以连接的圆圈标为A
  4. 重复2、3步直至所有可以连接的圆圈都被标上A或B
    如下图所示
    在这里插入图片描述
    图中有13个A,11个B
    由于A只能连B,B只能连A,所以假设能一条线连接24个点的话(该线的一个端点必然为左上角的A点)
    故该线段对应的必然是ABAB…这样AB交错的顺序,这种顺序,AB点的个数要么相等(如ABAB),要么A点比B点多1个点(如ABABA)
    但是13个A点,11个B点,必然有起码一个A点是无法通过AB交错的方式连接起来,
    即无法通过一条线来连接
1030 黑白连线 Description 给定直线上2n个点的序列P[1,2,… ,2n],每个点P[i]要么是白点要么是黑点,其中共有n个白点和n个黑点, 相邻两个点之间距离均为1,请设计一个算法将每个白点与一黑点相连,使得连线的总长度最小。例如,图中有 4个白点和4个黑点,以图中方式相连,连线总长度为1+1+1+5=8。 Input 第一行输入m表示有m组测试. 每组测试首先输入n(n<=10000),接下来输入2n个0或者1, 分别表示白色或者 黑色, 其中0和1的个数分别为n个. Ou 阅读详情

相关推荐

图案解锁(九宫解锁+九点解锁)

这是图案解锁的项目,对大家 很有帮助的 ,不妨下载学习学习

学校1007: 判断24点是否有解

Description 常玩的24点游戏其规则是:给出4个1到13可重复的数字。数字顺序不能改变。在数字间添加加、减、乘、除、括号,使运算结果为24。可以添加多个括号。有经验的玩家都知道并不是所有的4个数字都有解。判断给出的4个数字是否有解。  Input 第一行有一个数代表有多少组测试数据。每组数据占一行。分别有a、b、c、d (1 Output 每组数据对应一行输出。有解输

smartboysboys的专栏 6230

保姆级教程:用C++逆向解析通达信shm.tnf文件(附完整代码与偏移量详解)

本文提供了一份详细的C++逆向工程教程,指导开发者如何解析通达信的shm.tnf文件。通过分析文件结构、定位关键字段并实现完整解析流程,帮助量化交易开发者高效获取沪市股票数据。教程包含完整代码示例和偏移量详解,适合金融数据本地化处理需求。

weixin_27945229的博客 523

破解wx小游戏【一笔画完】(上)

最近朋友给我推荐的一个wx小游戏(一笔画完),游戏规则是一笔画完全部格子,不能重复,不能有空缺,休闲类游戏,感觉挺有意思的,于是我就是想用java来帮我实现通关这个游戏,游戏界面如下。(第一篇博客讲怎么破解,第二篇实现完全自动化)不管哪一关都可以用这个代码0.1s内自动破解找到答案!

qq_35425070的博客 1万+

K210视觉项目上位机避坑指南:解决C#解析ESP8266 TCP图像流的乱码、卡顿与连接中断

本文详细解析了K210与ESP8266在视觉项目中的上位机开发问题,重点解决TCP图像流解析中的乱码、卡顿与连接中断问题。通过自定义协议、JPEG流重组、TCP连接优化等实战技巧,提升系统稳定性和性能,适用于嵌入式视觉开发者和C#上位机程序员。

weixin_28730131的博客 402

从VLM到VLA概论

智驾视觉大模型

xiaomu_347的博客 1712

24点游戏探秘系列7: 24点无解局面清单

24点游戏探秘系列7:24点无解局面清单ococo 2003/2/10无解局面清单(共458个,约占25.2%):Question:1 1 1 1Question:1 1 1 2Question:1 1 1 3Question:1 1 1 4Question:1 1 1 5Question:1 1 1 6Question:1 1 1 7Question:1 1 1 9Question:

Java我的最爱 4828

ESP32 物联网宠物喂食器:实现远程智能投喂的完整方案

本项目基于 ESP32 实现了智能宠物喂食器的核心功能,硬件结构简单、成本较低,软件支持远程控制和状态监测。添加摄像头:通过 ESP32-CAM 模块实时观察宠物进食情况。APP 集成:开发专属手机 APP,支持定时设置、报警推送、喂食记录查询。语音控制:结合 Alexa 或小爱同学,实现语音指令喂食。太阳能供电:户外使用时,通过太阳能板为设备供电,节能环保。

weixin_42300449的博客 1275

24点游戏探秘系列7: 24点无解局面清单 (转)

24点游戏探秘系列7: 24点无解局面清单 (转)[@more@]24点游戏探秘系列7:24点无解局面清单 ococo 2003/2/10 无解局面清单(共458个,约占25.2%): Question:1 1 1 1Qu...

ciya3282的博客 977

【EDA Tools】Spyglass 检查 Verilog 和 SystemVerilog 混合语言及 Lint 检查

Spyglass可以用于检查混合设计中的语言互操作性和一致性问题。对于设计中包含多种硬件描述语言的情况,Spyglass 能够识别并解析其中的模块及其互连,并对其进行验证。例如,在包含 Verilog 和 VHDL 的混合设计中,Spyglass 会自动识别并解析 Verilog 和 VHDL 文件及其相互连接。通过运行 Spyglass Lint 功能,可以检查混合设计中的语言一致性问题,例如不兼容的数据类型、互操作性问题以及其他可能导致设计故障或不一致的问题。

记录学习历程 5080

物联网系列③——基于ESP8266与点灯科技平台的温湿度计设计(接入小爱同学)

物联网系列③——基于ESP8266与点灯科技平台的温湿度计设计(接入小爱同学)一、设计目标二、电路展示三、存在的问题四、代码五、需要注意的问题 一、设计目标       前一阵子偶然接触到点灯科技平台,产生了制作一块ESP8266电路板,拥有以下功能: 使用CH340对ESP8266进行程序下载 使用DHT11进行温湿度数据读取 使用点灯科技平台接入物联网,可通过手机APP获得室内温湿度 接入小爱同学,通过语音获取室内温湿度信息 Mico US

weixin_43278295的博客 8853

把所有圆圈连接起来的游戏_不过黑点,把所有圆圈连起来

公告: 为响应国家净网行动,部分内容已经删除,感谢读者理解。话题:不过黑点,把所有圆圈连起来。不能斜着连!求解~问题详情:说不能连黑点,没说不能绕开黑 |回答说简单,还没给出怎么走的回答:说不能连黑点,没说不能绕开黑点,看来确实很无解?只要从下面开始横着连,到上面遇到黑点的时候从上面空白处绕开即可!我个人认为这道题的难点不是图片而是字,要不然 看谁聪明 那几个大字下面就一空白行做何用呢这么多大神都...

weixin_42168555的博客 6416

ComfyUI报错ModuleNotFoundError: No module named ‘comfy.options‘

好家伙,我一想我刚刚好像用了pip安装了comfy模块,不会是和ComfyUI自带的comfy模块产生冲突了吧。(3)还有的说是项目不是最新版,叫更新到最新版本的,好家伙,我报错之前根本没更新也没错,突然就报错的。(4)还有的说没有comfy.options这部分代码,叫自己去拉一个,我一看也有啊。我也不知道啥时候脑抽风去装这么个东西的,幸好我聪明机智,一眼就知道了。看把我气的,然后网上搜集各种资料,一个一个去试。

满目星辰 5159

破解wx小游戏【一笔画完】(下)

上一篇博客分享了如何一笔画完的关卡破解,这篇博客分享一下自己做的一个demo,先上个动图 动图略大,需要加载。 源码在文章最后 下面开始正题,说一下我做的想法和过程,其中对二值化的过程做了一定优化 //选择进入 未通过 关卡 //破解当前关 //1.adb截屏传到电脑 //2.打开图片,创建副本,对其进行二值化,阈值24...

qq_35425070的博客 7364

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

24点的所有组合的解法

近日,试着研究24点的算法。觉得穷举法是一种可以接受的解法。利用时下的计算机。就是穷举从1,1,1,1到10,10,10,10的所有数字组合的解法也不过就几秒钟而已。而且,可以将所有的结果保存在文件里,以供日后其他应用时方便调用,加快计算速度。下面将有结果的组合和解法赋予其后,有兴趣的同道之人可以参阅。1,1,1,8   ---   8×(1+1+1)=241,1,2,6   ---  

万仓一黍 6811

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

一个和24点有关的算法题 - 无解中

“24点游戏是一种使用扑克牌来进行的益智类游戏,游戏内容是:从一副扑克牌中抽去大小王剩下52张,任意抽取4张牌,把牌面上的数(A代表1)运用加、减、乘、除和括号进行运算得出24。每张牌都必须使用一次,但不能重复使用。 有些组合有不同种算法,例如要用2,4,6,12四张牌组合成24点,可以有如下几种组合方法: 2 + 4 + 6 + 12 = 24  4 × 6 ÷ 2 + 12 = 24  1

houhouzhe的专栏 3648

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

一笔四线连9点你可以吗

按照九宫格的方式画九个点,每个点与上下左右相邻的点的距离相等。 如下: ●          ●          ● ●          ●          ● ●          ●          ● 问用一笔画四条直线将所有的点连接起来。(也就是除了第一条直线起始和最后一条直线结束外,每条直线必须首尾相连。)

XuXuemin的专栏 8289

下面有9个点的图片。你能一笔画出4条直线连接着9个点,并且不重复任何一条线吗?

下面有9个点的图片。你能一笔画出4条直线连接着9个点,并且不重复任何一条线吗?

JavaDevelopmentLearner 5万+

抖音5×5一笔连线问题无解的证明

最近抖音上突然出现了一个一笔连游戏,经证明这个是无解的!

weixin_43374551的博客 7万+

三行九个点,用4条线段连接(扩展,用3条,用1条)

题目:请使用4条线段连接以下9个点 。 。 。 。 。 。 。 。 。 答案; o ━━o ━o━━ ┃\ / ┃ \ / o o o ┃ \ / ┃ /\ o o o ┃ / \ ┃ / ┃/ 解析和扩展: 答案一:将纸折叠起来,使点所在的...

weixin_30311605的博客 1227

NYOJ 42一笔画问题

一笔画问题 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 zyc从小就比较喜欢玩一些小游戏,其中就包括画一笔画,他想请你帮他写一个程序,判断一个图是否能够用一笔画下来。 规定,所有的边都只能画一次,不能重复画。   输入第一行只有一个正整数N(N 每组测试数据的第一行有两个正整数P,Q(P 随后的Q行,每行有

I_am_growing的专栏 1102

分治法:给定平面上n个白点和n个黑点,试s合计一个分治算法江每个白点和黑点向量,所有连线互不相交

自己分析:采用分治方法,寻找合适的中间界限,将大区间问题分成左右两个子区间,不通过递归过程求解。当然在其中的选择方式有很多,我们只要找到其中一种就可以。具体思路就是把大问题分解成两个子问题,然后从子问题中递归计算。这道题也可以采用贪心算法求解,这里主要考虑分治算法。 算法分析: 我们设P1..Pn为白点,Pn+1..P2n为黑点。我们采取分治采取分治策略寻找序列[Pp..Pr]中的配对方案(初

u010244645的博客 6860

面试失败之24点算法

  周一风尘仆仆(上午6点抵达成都)的去参加了凡客成都研发中心的面试,虽然经历一夜的折腾让我感觉头脑很不清醒,不过这种面试状态也不错,能让我深刻体验一下在不清醒状态下进行的思考和回答问题。午饭过后便出了门,习惯了不堵车,突然觉得成都的交通真的很拥堵。到达凡客成都研发中心填完表后等了大概10多分钟,面试官把我带进会议室,开始了面试。面试过程为由3位技术大牛面试官轮番面试,他们问了很多有意义的技术和管...

weixin_34307464的博客 228
上一篇: Django自学笔记 1-1 新建项目(project)、应用(app)、运行项目
下一篇: Django自学笔记 4-2 模型(models)中的Field(字段)
大爽歌
博客等级 码龄9年 422粉丝 92原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值