算法设计与分析—神奇排列(回溯法)

算法设计与分析课程练习题:

题目、神奇排列
对于给定的正整数,多重集S ={1,1,2,2,3,3,… . , n, n}的2n个元素的神奇排列是指满⾜如下条件的排列:对于从1到n的每个整数,其两次出现之间的中间元素的数量等于该整数。例如,当n=3时,两种可能的神奇排列是3,1,2,1,3,2和2,3,1,2,1,3。
a) 基于回溯编写⼀个函数,输⼊参数是n,打印输出所有神奇排列的数量。统计并输出你的函数的调⽤次数。
b) 基于回溯编写⼀个函数,输⼊参数是n,打印输出1个神奇排列。统计并输出你的函数的调⽤次数。

a) 算法思路
1、先成一个长度为2n的数组path,用来记录结果,生成一个used集合,用来记录节点是否被使用过,再生成一个nums数组存储1~n的数据
2、遍历nums数组,如果没有被使用,则将数据x放入path中,同时将间隔长度为x的位置放上x,并在used中标记。回退时将used中的记录删去

"""
a) 基于回溯编写⼀个函数,输⼊参数是n,打印输出所有神奇排列的数量。
统计并输出你的函数的调⽤次数。
"""
times=0
def get_all_path(n):
    """
    :param n:
    :return: list[]
    """
    res=[]
    used = set()
    path = [0 for i in range(n * 2)]
    nums = [j for j in range(1, n + 1)]

    def track(i, j):
        global times
        times+=1
        if len(used) == n and j == n - 1:
            res.append(path[:])
            return
        if i + nums[j] + 1 >= 2 * n or nums[j] in used:
            return
        if path[i] != 0 or path[i + nums[j] + 1] != 0:
            track(i + 1, j)
        else:
            path[i] = nums[j]
            path[i + nums[j] + 1] = nums[j]
            used.add(nums[j])
            for k in range(n):
                track(i + 1, k)
            # print(path)
            path[i] = 0
            path[i + nums[j] + 1] = 0
            used.remove(nums[j])
    for i in range(n):
        track(0, i)
    return res
def test_1_1():
    global times
    for i in range(1, 10):
        res = get_all_path(i)
        print("n=%d时,神奇排列为:" % (i), res)
        print("递归次数:", times)
        times = 0

运行截图算法设计与分析—神奇排列(回溯法)_第1张图片
b) 算法思路
1、在a的基础上进行了改进,只要判断出一个神奇排列,就开始返回True,每次调用track递归函数时都要先进行判断,如果为True则运行结束,否则继续执行

times=0
def get_a_path(n):
    res = []
    used = set()
    path = [0 for i in range(n * 2)]
    nums = [j for j in range(1, n + 1)]

    def track(i, j):
        global times
        times += 1
        if len(used) == n and j == n - 1:
            res.append(path[:])
            return True
        if i + nums[j] + 1 >= 2 * n or nums[j] in used:
            return False
        if path[i] != 0 or path[i + nums[j] + 1] != 0:
            if track(i + 1, j):
                return True
        else:
            path[i] = nums[j]
            path[i + nums[j] + 1] = nums[j]
            used.add(nums[j])
            for k in range(n):
                if track(i + 1, k):
                    return True
            path[i] = 0
            path[i + nums[j] + 1] = 0
            used.remove(nums[j])

    for i in range(n):
        if track(0, i):
            return res
    return res

def test_1_2():
    global times
    for i in range(1, 10):
        res = get_a_path(i)
        print("n=%d时,神奇排列为:" % (i), res)
        print("递归次数:", times)
        print()
        times = 0

算法设计与分析—神奇排列(回溯法)_第2张图片

你可能感兴趣的:(算法设计与分析,#回溯法,算法,python,回溯法)