第三天
到目前为止,我们的进展都很顺利。不过我们的代码速度还不是很快,应该还有改进的余地。
昨天我们使用第一行生成了一个包含2^n个序列的list,我们认真看看,就会发现中间很多是对称的,比如n=3的时候100,001对称, 110,011对称。按照我们的算法,这些对称的的序列最后得到的开关桩状态也是对称的,那么我们把每得到一个解,就可以把对称的第一行组合去掉。那么同 理,如果第一行的某一个组合不是解,那么我们也可以把他去掉。这样不就减少了很多的循环次数啦。
首先判断list是否对称:
- def symmetric(alist):#判断list是否对称
- leng=len(alist)
- le=alist[:(leng/2)]
- ri=alist[-(leng/2):]
- ri.reverse()
- if le!=ri:
- alist.reverse()
- return alist
- else:
- return None
其他的都一样,我们在昨天的基础上修改一下就好了:
- def light(n):
- PosSol = [nastr.array(bstr(x).zfill(n), itemsize=1).eval().tolist() for x in xrange(2**n)]
- solution=zeros((n, n))#解
- tmpArray=zeros((2, n+2))#用来存放每一行的开关状态
- try:
- for i in range(len(PosSol)):
- i=PosSol[i][:]
- solution[0:1]=i
- tmpArray[0, :]=0
- tmpArray[1,1:-1]=i
- for line in range(n-1):#取n-1是因为第一行是生成的,不需要计算
- solution[line+1:line+2, :]=ones((1, n))-lightstats(tmpArray, n)
- tmpArray[:,1:-1]=solution[line:line+2, :]
- if sum(lightstats(tmpArray, n))==n:
- steps=sum(sum(solution))
- print solution
- print "Total steps:%d" % steps
- rev=symmetric(i)
- if rev!=None:
- print solution[:,::-1]
- print "Total steps:%d" % steps
- PosSol.remove(rev)
- except:
- pass
注意for i in range(len(PosSol))这句,这个是很多初学python的人在循环上犯的错。但是我们这里这么作是有原因的。在如果直接写for i in PosSol,那么在循环体中间对PosSol的操作不会得到你想要的结果,所以我们这样避免了这样的问题。i=PosSol[i][:]是产生一个拷 贝。免得对PosSol里面产生影响。
下面就是代码:
- #!/usr/bin/python
- # -*- coding: utf8 -*-
- #Filename:third2.py
-
- from numarray import *
- import numarray.strings as nastr
- from bin import bstr
-
- def lightstats(switchstats, n):
- TxT = [take(switchstats, [x, x+1, x+2], axis=1) for x in range(n)]
- [putmask(item, [1,0,1,0,0,0], [0]) for item in TxT]#去掉不相关的格子
- return [(sum(sum(item)))%2 for item in TxT]
-
- def symmetric(alist):#判断list是否对称
- leng=len(alist)
- le=alist[:(leng/2)]
- ri=alist[-(leng/2):]
- ri.reverse()
- if le!=ri:
- alist.reverse()
- return alist
- else:
- return None
-
- def light(n):
- PosSol = [nastr.array(bstr(x).zfill(n), itemsize=1).eval().tolist() for x in xrange(2**n)]
- solution=zeros((n, n))#解
- tmpArray=zeros((2, n+2))#用来存放每一行的开关状态
- try:
- for i in range(len(PosSol)):
- i=PosSol[i][:]
- solution[0:1]=i
- tmpArray[0, :]=0
- tmpArray[1,1:-1]=i
- for line in range(n-1):#取n-1是因为第一行是生成的,不需要计算
- solution[line+1:line+2, :]=ones((1, n))-lightstats(tmpArray, n)
- tmpArray[:,1:-1]=solution[line:line+2, :]
- if sum(lightstats(tmpArray, n))==n:
- steps=sum(sum(solution))
- print solution
- print "Total steps:%d" % steps
- rev=symmetric(i)
- if rev!=None:
- print solution[:,::-1]
- print "Total steps:%d" % steps
- PosSol.remove(rev)
- except:
- pass
-
- if __name__ == "__main__":
- tests = [2,3,4,5,6,7,8,9,10]
- for xx in tests:
- print "solution for %d*%d" % (xx,xx)
- light(xx)
既然可以用对称得到解,那么也可以用对称排除不是解的组合:
- def light(n):
- PosSol = [nastr.array(bstr(x).zfill(n), itemsize=1).eval().tolist() for x in xrange(2**n)]
- solution=zeros((n, n))#解
- tmpArray=zeros((2, n+2))#用来存放每一行的开关状态
- try:
- for i in range(len(PosSol)):
- i=PosSol[i][:]
- solution[0:1]=i
- tmpArray[0, :]=0
- tmpArray[1,1:-1]=i
- for line in range(n-1):#取n-1是因为第一行是生成的,不需要计算
- solution[line+1:line+2, :]=ones((1, n))-lightstats(tmpArray, n)
- tmpArray[:,1:-1]=solution[line:line+2, :]
- rev=symmetric(i)
- if sum(lightstats(tmpArray, n))==n:
- steps=sum(sum(solution))
- print solution
- print "Total steps:%d" % steps
- if rev!=None:
- print solution[:,::-1]
- print "Total steps:%d" % steps
- PosSol.remove(rev)
- else:
- if rev!=None:
- PosSol.remove(rev)
- except:
- pass
这是新的light函数。不过我们想想,我们可以把解进行旋转,得到的就是其他的解,但是不是解的组合不能旋转排除哦,原因嘛,想想就明白了。我们写一个旋转的函数:
- def rotatearray(array):
- o=zeros(shape(transpose(a)))
- for i in range(len(a)):
- b[:,i]=a[i,::-1]
- return o
那么就是修改以后的light函数:
- def light(n):
- allSolutions=[]
- PosSol = [nastr.array(bstr(x).zfill(n), itemsize=1).eval().tolist() for x in xrange(2**n)]
- solution=zeros((n, n))#解
- tmpArray=zeros((2, n+2))#用来存放每一行的开关状态
- try:
- for i in range(len(PosSol)):
- i=PosSol[i][:]
- solution[0:1]=i
- tmpArray[0, :]=0
- tmpArray[1,1:-1]=i
- for line in range(n-1):#取n-1是因为第一行是生成的,不需要计算
- solution[line+1:line+2, :]=ones((1, n))-lightstats(tmpArray, n)
- tmpArray[:,1:-1]=solution[line:line+2, :]
- if sum(lightstats(tmpArray, n))==n:
- steps=sum(sum(solution))
- temp=solution
- for j in range(2):
- for k in range(4):
- temp=rotateArray(temp)
- if temp.tolist() not in allSolutions:
- allSolutions.append(temp.tolist())
- print temp
- print "Total steps:%d" % steps
- try:
- PosSol.remove(temp[0, :].tolist())
- except:
- pass
- temp=transpose(temp)
- else:
- try:
- PosSol.remove(rev)
- except:
- pass
- except:
- pass
我们去掉了判断对称的函数,直接使用remove,跳过错误信息。定义了allSolutions来避免重复。
现在来总测试一下我们的成果吧:
程序 n 时间
first.py 2~4 real 3m16.271s
second.py 2~10 real 2m32.655s
second2.py 2~10 real 2m38.275s
third.py 2~10 real 2m28.386s
third2.py 2~10 real 1m32.934s
third3.py 2~10 real 1m17.786s
