Python回溯算法
Posted
技术标签:
【中文标题】Python回溯算法【英文标题】:Backtracking algorithm with Python 【发布时间】:2012-02-17 06:38:59 【问题描述】:我正在尝试实现一种算法,该算法采用两个整数 n 和 k,其中 n 是一排座位的数量,k 是试图坐在该排的学生数量。问题是每个学生必须在两边至少有两个座位。我拥有的是一个生成所有子集的函数(一个 0 或 1 的数组,1 表示有人坐在那里),我将它发送到一个函数以检查它是否是一个有效的子集。这是我用于该功能的代码
def process(a,num,n):
c = a.count('1')
#If the number of students sitting down (1s) is equal to the number k, check the subset
if(c == num):
printa = True
for i in range(0,n):
if(a[i] == '1'):
if(i == 0):
if( (a[i+1] == '0') and (a[i+2] == '0') ):
break
else:
printa = False
elif(i == 1):
if( (a[i-1] == '0') and (a[i+1] == '0') and (a[i+2] == '0') ):
break
else:
printa = False
elif(i == (n-1)):
if( (a[i-2] == '0') and (a[i-1] == '0') and (a[i+1] == '0') ):
break
else:
printa = False
elif(i == n):
if( (a[i-2] == '0') and (a[i-1] == '0') ):
break
else:
printa = False
else:
if( (a[i-2] == '0') and (a[i-1] == '0') and (a[i+1] == '0') and (a[i+2] == '0') ):
break
else:
printa = False
if(printa):
print a
else:
return
该代码适用于 k 和 n 的小输入,但如果我得到更高的值,我会因为某种原因得到一个索引超出列表错误,我无法弄清楚。 任何帮助都非常感谢。
O 输入 a 是看起来像这样的列表
['1','0','0','1','0'] # a valid subset for n=5 and k=2
['0','0','0','1','1'] # an invalid subset
编辑:
调用进程的代码:
'''
This function will recursivly call itself until it gets down to the leaves then sends that
subset to process function. It appends
either a 0 or 1 then calls itself
'''
def seatrec(arr,i,n,k):
if(i==n):
process(arr,k,n)
return
else:
arr.append("0")
seatrec(arr,i+1,n,k)
arr.pop()
arr.append("1")
seatrec(arr,i+1,n,k)
arr.pop()
return
'''
This is the starter function that sets up the recursive calls
'''
def seat(n,k):
q=[]
seat(q,0,n,k)
def main():
n=7
k=3
seat(n,k)
if __name__ == "__main__":
main()
如果我使用这些数字,我得到的错误是
if( (a[i-2] == '0') and (a[i-1] == '0') and (a[i+1] == '0') ):
IndexError: list index out of range
【问题讨论】:
请包含导致错误的对process
的具体调用,包括a、num和n的值,以便我们重现它。还请发布错误消息,以便我们知道它发生在哪一行:-)
【参考方案1】:
排除无效的座位安排就足够了,即当学生彼此相邻的座位['1', '1']
或他们之间只有一个座位['1', '0', '1']
时,所有其他具有正确编号'1'
的安排,以及'0'
有效,example:
def isvalid(a, n, k):
if not isinstance(a, basestring):
a = ''.join(a) # `a` is a list of '1', '0'
return (len(a) == n and a.count('1') == k and a.count('0') == (n-k) and
all(p not in a for p in ['11', '101']))
有更有效的算法来生成有效子集而不检查所有子集,例如,
def subsets(n, k):
assert k >= 0 and n >= 0
if k == 0: # no students, all seats are empty
yield '0'*n
elif k == 1 and (n == 1 or n == 2): # the last student at the end of the row
yield '1' + '0'*(n-1) # either '1' or '10'
if n == 2: yield '01'
elif n > 3*(k-1): # there are enough empty seats left for k students
for s in subsets(n-3, k-1):
yield '100' + s # place a student
for s in subsets(n-1, k):
yield '0' + s # add empty seat
Example
n, k = 5, 2
for s in subsets(n, k):
assert isvalid(s, n, k)
print(s)
输出
10010
10001
01001
【讨论】:
【参考方案2】:长度为n
的数组的索引从0
到n-1
。因此访问n
不在列表中。
如果您在较小的值上没有注意到这一点,那么生成列表的代码肯定有错误。
【讨论】:
您具体在哪里看到数组访问 n?range(0, n)
不包括 n
当 i == (n-1) 时,访问 a[i+1]。这等于 a[n]以上是关于Python回溯算法的主要内容,如果未能解决你的问题,请参考以下文章
leetcode 46 Permutations Python 实现(回溯算法)
leetcode-46. 全排列--回溯算法--python