回溯法非详解(邪恶)python

一、回溯是什么?

我觉得可能就是一种好听的学术的暴力遍历,当然加上剪枝以后就会高大上一些,不过暴力遍历也能加简化条件就是了

二、实例

1.回溯法模板

回溯法理解了以后就可以套模板了,这里是我自己定义的模板:

def backtrack(A,re):
	if A 满足条件:
		re.append(A)
	for i in 可选择的下一状态:
		if 可以剪枝:
			剪枝
		A.append(i)
		backtrack(A,re)
		A.remove(i) #remove了没有关系,因为满足条件的项已经加入re了

2.实例:求子集

这里用了一种回溯发,也可以用二进制代表法,下图是非二进制代表法的回溯图:
在这里插入图片描述

def subset(A,S,re,te):
	if A not in re:
		re.append(A[:])
	for i in range(te,len(S)):
		t,te=S[i],i
		A.append(t)
		subset(A,S,re,te+1)
		A.remove(t)
re=[]
subset([],[1,2,3],re,0)	
print(re)

3.实例:做数独

为了偷懒呢,我这里只做了一个3*3的数独格子,且需要满足的条件也只有横竖都有123即可,比较增加条件只需要在模板的 if 中添加即可,没有什么技术难题:

import copy
def isSafe(A):
	mode=[x for x in range(1,len(A)+1)]
	for i in range(1,len(A)+1):
		t=mode[:]
		for j in range(1,len(A)+1):
			if A[i-1][j-1] in t:
				t.remove(A[i-1][j-1])
			else:
				return False
	for i in range(1,len(A)+1):
		t=mode[:]
		for j in range(1,len(A)+1):
			if A[j-1][i-1] in t:
				t.remove(A[j-1][i-1])
			else:
				return False
	return True 
def find_emp(A):     #寻找还没填数的下标
	r=[]
	for i in range(len(A)):
		for j in range(len(A)):
			if A[i][j]==0:
				r.append([i,j])
	return r
def sudoku(A,re):
	emp_pos=find_emp(A)
	if isSafe(A) and A not in re and len(emp_pos)==0:
		re.append(copy.deepcopy(A))
	elif len(emp_pos)>0:
		for x in range(1,4):
			emp_pos=find_emp(A)
			i,j=emp_pos[0]
			A[i][j]=x
			sudoku(A,re)
			A[i][j]=0
re=[]
A=[[0,3,0],[0,0,1],[2,0,0]]
sudoku(A,re)
print(re)

总结

回溯法想明白了真的不难,没想明白前真的很难,其实回头想起来最关键的点就是为什么可以remove?因为remove前已经把答案加入re啦!如果回溯法不递归那么一下就和暴力没什么区别,所以emmm好吧

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值