判别数字图片能否「一笔完成」
每张给定的数字图片只有2种像素值,即0和255,如下所示:

现给定全黑的一张背景图,用一支笔可以连续地在上下左右斜对角共8个方向移动,可以允许重复地经过一处。笔经过处像素值会变为0,即变成白色。如果这样操作后能得到一张如上所示的数字图片,则称该数字图片可以「一笔完成」。
下面是不能「一笔完成」的数字图片例子:

因为要完成“6”中间部分的「白圈」,必须要把「笔」拿起来放到对应的位置移动。
将数字“6”用pandas可视化如下所示,这里去掉像素值全为0的部分列:
也就说,需要给定一个程序判断是否有一堆「0」被一堆「255」围住,如果是的话,这张数字图片就是不能「一笔完成」的。我这里用的办法是深度搜索,往上下左右4个方向深搜,判断图片中有几堆「0」。如果仅有1堆,那么这个数字图片可以「一笔完成」;反之。
代码
import numpy as np
# 读取函数,数据都被保存在mnist.npz
def load_data():
data = np.load('./mnist.npz')
X = data['X']
return X
def DFS(X, row, col, visited):
visited[row][col] = 1
if X[row][col] == 255:
return
if row+1 < 28 and visited[row+1][col] == 0:
DFS(X, row+1, col, visited)
if col+1 < 28 and visited[row][col+1] == 0:
DFS(X, row, col+1, visited)
if row-1 >= 0 and visited[row-1][col] == 0:
DFS(X, row-1, col, visited)
if col-1 >= 0 and visited[row][col-1] == 0:
DFS(X, row, col-1, visited)
if __name__ == '__main__':
X = load_data()
# X.shape = (10000, 28, 28)
success = 0 # 可以「一笔完成」的数字图片总数
for t in range(10000):
blocks = 0 # 数字图片中存在几堆「0」
visited = np.zeros((28, 28)) # 标记数组
for i in range(28):
for j in range(28):
if X[t][i][j] == 0 and visited[i][j] == 0:
DFS(X[t], i, j, visited)
blocks += 1
if blocks == 1:
success += 1
print(success)