家里新购了一个数独,周四午餐后消食便拿起来玩,半小时过去了,一小时过去了,一直没成功……超级不服气的,这道难题想逼我是吗?干脆直接写python代码破解好了!半小时后代码还没写好,我被本身蠢哭了。在写代码这件事上,我显然手生得很呢。值得欣慰的是,我起码知道生物脑没法完成的,电脑能够代劳,只不过这代码依然须要生物脑来完成。python
趁着端午小长假有点时间,就来琢磨下这件事好了。算法
计算目标:找到数独的答案。是找一些答案,仍是找出全部答案呢?后者难度高,且包含前者,我选择后者。框架
数独规则:在下述六角形棋盘的12个位置中分别放入数字1至12,使得图中每条连线4个位置加和为26。dom
个人生物脑是如未尝试解出答案的呢?函数
从棋盘取下全部数字,先随意选择4个数字放入某条线使之加和为26,而后再选择3个数字放入与此线有交点的另一条线使之加和为26,而后尝试第3条线……结果是,每次尝试到第三、4条线时开始吃力,偶尔能知足5条线但最后一条线没法知足条件。优化
我将如何用代码来指挥电脑演算呢?用代码复原生物脑的思路,显然是很是蠢的解法。大家知道我是如何知道本身蠢的吗?由于上述思路拆解出来就是:spa
我彻底没法快速用代码表达出以上思路,基于此不难自我判断上述算法是愚蠢的。code
通过一些摸索后,我把碳基问题抽象为下述硅基问题:cdn
import math
import random
def areyouwin(point_list):
if point_list[0] + point_list[6] + point_list[11] + point_list[4] != 26 :
return False
elif point_list[0] + point_list[7] + point_list[8] + point_list[2] != 26 :
return False
elif point_list[1] + point_list[7] + point_list[6] + point_list[5] != 26 :
return False
elif point_list[1] + point_list[9] + point_list[8] + point_list[3] != 26 :
return False
elif point_list[4] + point_list[9] + point_list[10] + point_list[2] != 26 :
return False
elif point_list[3] + point_list[10] + point_list[11] + point_list[5] != 26 :
return False
else:
return True
point_list = [1,2,3,4,5,6,7,8,9,10,11,12]
k = 0
while k < 10 :#此处k表示找出10个答案,想要更多答案就改k的值便可
random.shuffle(point_list)#新知识点:随机打乱列表
if areyouwin(point_list):
print(point_list,k+1)
k = k + 1
复制代码
初步搜索,我没有找到如何实现输出列表项所有的排列组合。鉴于很是清楚本身对排列组合的代码实现接近于0经验,因而故意想要本身写代码实现。blog
计算目标的大框架已经实现,如今只缺排列组合。那我聚焦于此:
子目标:输出天然数1至12的全部排列组合
演算方法是怎样的呢?
这个演算方法可行吗?代码将如何写?彷佛有些困难。那我我先试着简化问题:输出天然数1至3的全部排列组合。并写出代码来验证结果是否正确。
point_list = [1,2,3]
#列表A赋值给列表B时须要用切片的方式,不然列表B改变时会引起列表A改变!
point_1_list = point_list[:]
for i in point_1_list:#实现位置1的循环
point_2_list = point_1_list[:]
point_2_list.remove(i) #位置2的取值范围是位置1的取值范围移除位置1的当前值
#print(point_2_list)
for j in point_2_list:
#print(j,"j的值")
point_3_list = point_2_list[:]
point_3_list.remove(j)#位置3的取值范围是位置2的取值范围移除位置1的当前值
k = point_3_list[0]#位置3的取值范围只剩1个数值
print(i,j,k)#打印排列组合结果
复制代码
在完成上述代码的过程当中,刚开始列表赋值并无采用切片的方式,致使全部列表均发生改变。无他,仍是反映我对列表的操做不熟。
先不论代码是否简洁优雅,至少它在功能上实现了。那么如今,先试着用这个思路实现天然数1至12的所有排列组合,并计算得出数独26的解法共有多少个!
下面就是不简洁不优雅版本的数独全部答案的代码:
def areyouwin(point_list):
if point_list[0] + point_list[6] + point_list[11] + point_list[4] != 26 :
return False
elif point_list[0] + point_list[7] + point_list[8] + point_list[2] != 26 :
return False
elif point_list[1] + point_list[7] + point_list[6] + point_list[5] != 26 :
return False
elif point_list[1] + point_list[9] + point_list[8] + point_list[3] != 26 :
return False
elif point_list[4] + point_list[9] + point_list[10] + point_list[2] != 26 :
return False
elif point_list[3] + point_list[10] + point_list[11] + point_list[5] != 26 :
return False
else:
return True
point_list = [1,2,3,4,5,6,7,8,9,10,11,12]
#列表A赋值给列表B时须要用切片的方式,不然列表B改变时会引起列表A改变!
point_1_list = point_list[:]
for p_1 in point_1_list:#实现位置1的循环
point_2_list = point_1_list[:]
point_2_list.remove(p_1) #位置2的取值范围是位置1的取值范围移除位置1的当前值
for p_2 in point_2_list:
point_3_list = point_2_list[:]
point_3_list.remove(p_2)#位置3的取值范围是位置2的取值范围移除位置1的当前值
for p_3 in point_3_list:
point_4_list = point_3_list[:]
point_4_list.remove(p_3)
for p_4 in point_4_list:
point_5_list = point_4_list[:]
point_5_list.remove(p_4)
for p_5 in point_5_list:
point_6_list = point_5_list[:]
point_6_list.remove(p_5)
for p_6 in point_6_list:
point_7_list = point_6_list[:]
point_7_list.remove(p_6)
for p_7 in point_7_list:
point_8_list = point_7_list[:]
point_8_list.remove(p_7)
for p_8 in point_8_list:
point_9_list = point_8_list[:]
point_9_list.remove(p_8)
for p_9 in point_9_list:
point_10_list = point_9_list[:]
point_10_list.remove(p_9)
for p_10 in point_10_list:
point_11_list = point_10_list[:]
point_11_list.remove(p_10)
for p_11 in point_11_list:
point_12_list = point_11_list[:]
point_12_list.remove(p_11)
p_12=point_12_list[0]
one_list=[p_1, p_2, p_3, p_4, p_5, p_6, p_7, p_8, p_9, p_10, p_11, p_12]
if areyouwin(one_list):
print(one_list)
复制代码
上述代码for循环嵌套代码部分,不够简洁优雅。如何优化,是我接下来须要再琢磨的。笨办法也是办法,终于把数独的答案所有演算出来了,终于能安心睡个好觉了。
这就完了吗?固然不!这个碳基转硅基的解决方式中,有个内核的问题是,棋盘是个对称的六角星型,因而碳基世界的正确答案,其实只需硅基代码演算出答案的1/6。
以正确答案[1,2,3,6,11,7,5,12,10,8,4,9]为例,棋盘每转动60°就产生一个新答案: [2,3,6,11,7,1,12,10,8,4,9,5] [3,6,11,7,1,2,10,8,4,9,5,12] [6,11,7,1,2,3,8,4,9,5,12,10] [11,7,1,2,3,6,4,9,5,12,10,8] [7,1,2,3,6,11,9,5,12,10,8,4]
咿??如何优化代码,能撇掉那5/6臃肿的答案呢?——难度超纲,我仍是暂时放下吧。
代码写得好很差,手熟与否很关键呀!而手熟并不是简单的常常写就够了,而是要专门分解出哪些基础功或知识点薄弱,并重点突破之。此乃大咖们常曰的“刻意练习”。