2.回溯法

2回溯法

回溯法是一个求解“全部解”问题的方法。
回溯法是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法。而满足回溯条件的某个状态的点称为“回溯点”。

2.1八皇后问题

第一 分别尝试所有的位置。
第二 可以分别尝试所有的位置,前提条件是这个位置不能和已有的皇后冲突,只能放第二排。
第三 可以分别尝试所有的位置,前提条件是这个位置不能和已有的皇后冲突,只能放第三排。

结束条件:
第八个皇后放完以后。

# 八皇后问题

存储空间
board = [
    [0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0]
]

# 方案数量
total = 0


def can_place(x, y):
    # 判断(x,y)坐标能否放皇后
    # 1.判断x行是否有皇后
    for i in range(0, y):
        if board[x][i] == 1:
            return False
    # 2.判断y列是否有皇后
    for i in range(0, x):
        if board[i][y] == 1:
            return False
    # 3.判断斜线"/"方向是否有皇后
    # 第i行对应位置的列标为x+y-i
    for i in range(0, x):
        if x + y - i <= 7 and board[i][x + y - i] == 1:
            return False
    # 4. 判断"\"方向是否有皇后
    # index:0->(x-1),i:(x-1)->0
    for index, i in enumerate(range(x - 1, -1, -1)):
        s_y = y - (index + 1)
        if s_y >= 0:
            if board[i][s_y] == 1:
                return False
    return True


def print_board():
    # 打印方案
    for i in range(8):
        for j in range(8):
            if board[i][j] == 0:
                print("□ ", end=" ")
            else:
                print("■ ", end=" ")
        print()


def put_queen(step):
    # 八皇后问题迭代
    if step == 8:
        print_board()
        global total
        total += 1
        print("-----------------------------------------")
    else:
        for i in range(8):
            # 判断该位置是否能放置当前皇后
            if can_place(step, i):
                # 1.设置现场
                board[step][i] = 1
                # 2.开始递归
                put_queen(step + 1)
                # 3.恢复现场
                board[step][i] = 0


if __name__ == "__main__":
    put_queen(0)
    print("总共有{}种方法".format(total))

运行结果:
在这里插入图片描述

2.2全排列问题

# 全排列问题
# 1.老大 选择一个,剩余的交给老二
# 2.老二 选择一个,剩余的交给老三

data_list = [1, 2, 3, 4, 5]

arranges = []  # 排列方案
total = 0  # 方案数


def search(depth, datas):
    if depth == len(data_list) + 1:
        # arranges.append(datas[0])
        print(arranges)
        # arranges.pop()
        global total
        total += 1
    else:
        for data in datas:
            # 1.设置现场
            arranges.append(data)
            # 2.递归
            next_datas = datas[:]
            next_datas.remove(data)
            search(depth + 1, next_datas)
            # 3.恢复现场
            arranges.pop()


if __name__ == "__main__":
    search(1, data_list)
    print("共有{}种排列方式".format(total))

2.3数字拆分算法

# 1.老大拿到这个数之后,先尝试所有可能的取值,上一个分给自己的值

datas = []  # 存放组合方案

total = 0  # 方案总数


def search(rest):
    if rest <= 0:
        print(datas)
        global total
        total += 1
    else:
        for i in range(1, rest + 1):
            # 1.设置现场
            datas.append(i)
            # 2.递归
            search(rest - i)
            # 3.恢复现场
            datas.pop()


if __name__ == "__main__":
    num = 7  # 要被插的数
    search(num)
    print("方案数有{}种".format(total))

运行结果:
在这里插入图片描述

2.4总结

八皇后问题和全排列问题的迭代次数是固定的,相对来说会比较简单;数字拆分算法迭代次数是动态变化的。
回溯法的核心流程分为三部分:

  1. 设置现场。将当前数据放到结果集。
  2. 迭代。
  3. 恢复现场。将刚刚放的到结果集中的数据取出来,方便下一次迭代。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值