详解欧拉计划第349题:兰顿的蚂蚁

这篇博客探讨了欧拉计划第349题——兰顿的蚂蚁问题。通过小海龟模拟和matplotlib图像分析,揭示了蚂蚁行走的周期性模式。在1018次移动后,发现大约每104步会增加12个黑色方格,为解决问题提供了计算思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本题难度系数为35%(最易5%,最难100%)。

一只蚂蚁在涂有黑色或白色的普通方格上移动。蚂蚁总是朝向四种基本方向(左、右、上、下)之一,每次遵循以下规则移动到相邻的方格:

  • 如果它在黑色方格上,它将方格的颜色变为白色,逆时针旋转90度,向前移动一个方格
  • 如果它在白色方格上,它将方格的颜色变为黑色,顺时针旋转90度,向前移动一个方格

从全白的网格开始,在蚂蚁移动 1 0 18 10^{18} 1018次之后,有多少个方格是黑色的?


解:

小海龟模拟画图

用小海龟模拟蚂蚁的行为。

import turtle as tt
from collections import defaultdict

tt.screensize(bg="green")
tt.speed(9)
tt.left(90) # 让小海龟朝正北方向
tt.penup()
x, y = 0, 0
dx, dy = 0, 1
colors = defaultdict(int)
while True:
    if colors[(x, y)]:
        tt.left(90)
        dx, dy = -dy, dx
    else:
        tt.right(90)
        dx, dy = dy, -dx

    colors[(x, y)] = 1 - colors[(x, y)]

    x, y = x+dx, y+dy
    if colors[(x, y)]:
        tt.color('green')
    else:
        tt.color('black')
    tt.write('■', align='center', font=("Consolas", 10, "normal"))
    tt.forward(10)

一开始看不出明显的规律,一直走了1万多步之后,它进入到一种无限循环的模式。
在这里插入图片描述
录了一小段动画,看一下效果。

在这里插入图片描述
网上也有人写过类似的代码,实现方式与我的不一样。

# https://www.geeksforgeeks.org/python-langtons-ant/
import turtle


def langton():
    window = turtle.Screen()
    window.bgcolor('white')
    window.screensize(1000, 1000)

    maps = {}

    ant = turtle.Turtle()
    ant.left(90)
    ant.shape('square')
    ant.shapesize(0.5)
    ant.speed(999)
    pos = coordinate(ant)

    while True:
        step = 10
        if pos not in maps or maps[pos] == "white":
            ant.fillcolor("black")
            ant.stamp()
            invert(maps, ant, "black")
            ant.right(90)

            ant.forward(step)
            pos = coordinate(ant)

        elif maps[pos] == "black":
            ant.fillcolor("white")
            invert(maps, ant, "white")

            ant.stamp()
            ant.left(90)
            ant.forward(step)
            pos = coordinate(ant)


def invert(graph, ant, color):
    graph[coordinate(ant)] = color


def coordinate(ant):
    return (round(ant.xcor()), round(ant.ycor()))


langton()

确定重复模式

小海龟画图太慢,用matplotlib生成多幅图片,寻找规律。为了让图像向第一象限生长,初始小蚂蚁的方向朝南。

import matplotlib.pyplot as plt
import numpy as np


def black_squares(steps):
    x, y = 0, 0
    dx, dy = 0, -1  # 一开始蚂蚁朝南,这样图形会向第一象限无限循环
    blacks = set()
    for i in range(1, steps+1):
        if (x, y) in blacks:
            blacks.remove((x, y))
            dx, dy = -dy, dx
        else:
            blacks.add((x, y))
            dx, dy = dy, -dx
        x, y = x + dx, y + dy
    return blacks


def langton_pic(steps):
    b0 = black_squares(steps)
    fig, ax = plt.subplots()
    xs = [p[0] for p in b0]
    ys = [p[1] for p in b0]
    ax.plot(xs, ys, 's', markersize=3, markerfacecolor='black',
            markeredgecolor='green', markeredgewidth=0.1)
    ax.set_aspect('equal')
    ax.axhline(color='green', linewidth=0.6, linestyle='-')  # 水平轴
    ax.axvline(color='green', lw=0.6, ls='-')
    ax.set_xlim(-30, 80)
    ax.set_ylim(-30, 50)
    ax.set_title(f"langton's ant {steps}")
    ax.text(45, 45, f'black squares: {len(b0)}')
    plt.savefig(f'd://langton_ant/{steps}.png', dpi=200)
    plt.close()


for step in range(10000, 11000, 50):
    langton_pic(step)

仔细分析几幅图片,可以发现大概10500步之后,每104步,右边的茶壶嘴“长”了一小截。黑色方块多出12块。
在这里插入图片描述
在这里插入图片描述
现在可以计算出正确答案了,这里先随便找了一个大于10500的整数:12000,计算10**18距离12000要重复的次数,再计算出最初的步数,累加即可。

repeat = (10**18 - 12000) // 104
start = 10**18 - repeat * 104
print(len(black_squares(start)) + repeat * 12)

其它参考

网上关于这个问题的资料非常多,列出几个:

https://en.wikipedia.org/wiki/Langton%27s_ant

http://www.langtonant.com/

https://josephpetitti.com/ant

https://golly.sourceforge.net/webapp/golly.html

https://en.wikipedia.org/wiki/Golly_(program)

https://en.wikipedia.org/wiki/Hashlife

https://pypi.org/project/python-lifelib/2.0.9/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

申龙斌

撸代码来深夜,来杯咖啡钱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值