【问题标题】:How to make this breadth first search faster?如何使这种广度优先搜索更快?
【发布时间】:2019-02-27 16:46:37
【问题描述】:

我有一个搜索算法,它查找加法和乘法函数的组合,以从某个数字范围内达到某个数字范围。它正在搜索最短的程序,一个类似于 AAMMA 的程序,其中初始数字相加、相加、相乘、相乘、相加,其中结束数字在 r 到 s 范围内。它必须适用于起始范围 p 到 q 中的每个数字。

输入是 a 和 m,每个函数的相加和乘以 (num+a), (num*m)。我正在做的是尝试每种功能组合,直到找到一个有效的组合,如果它变得太大,则停止该分支。如果我找到有效的“程序”,我会在起始范围内的所有其他数字上尝试该程序。它会这样做,直到它没有找到不超过范围的分支。

我知道搜索不是超级典型,但我认为没有重复的可能性,所以我没有包含找到的列表。

它适用于较小的范围和输入,例如

Problem3("1 2 2 3 10 20")

但是对于更大的范围,我的测试用例只需要永远

Problem3("8 13 28 91 375383947 679472915")

我什至还没有看到完整的。从这里我最好的方法是什么,多线程(希望不是),以某种方式使我的内部功能更快,或者只是刮掉这种方法。

def Problem3(s):
    a,m,p,q,r,s = list(map(int, s.split(" ")))

    print(str(a) + "-C-" + str(m) + " processor")
    print("Input guarenteed between " + str(p) + " and " + str(q))
    print("Output is real number between " + str(r) + " and " + str(s))

    open_set = queue.Queue()
#   curr path depth
    open_set.put([p, "", 0])

    while not open_set.empty():

        subroot = open_set.get()

        multiCurr = subroot[0] * m
        addCurr = subroot[0] + a
        depth = subroot[2] + 1

        if r <= addCurr <= s:
            truePath = True
            #If we find a working path, we need to check if it works for the other things
            path = subroot[1] + "A"
            for x in range(p, q+1):
                for op in path:
                    if op == "A":
                        x += a
                    if op == "M":
                        x *= m
                if r <= x <= s:
                    pass
                else:
                    truePath = False
                    break
            if truePath:
                print("Found " + path + " at depth " + str(depth) + " with starting number " + str(p) + ", output " + str())

        if r <= multiCurr <= s:
            truePath = True
            path = subroot[1] + "M"
            for x in range(p, q+1):
                for op in path:
                    if op == "A":
                        x += a
                    if op == "M":
                        x *= m
                if r <= x <= s:
                    pass
                else:
                    truePath = False
                    break
            if truePath:
                print("Found " + path + " at depth " + str(depth) + " with starting number " + str(p) + ", output " + str())

        if addCurr > s and multiCurr > s:
            pass
        elif multiCurr > s:
            open_set.put([addCurr, subroot[1] + "A", depth])
        elif addCurr > s:
            open_set.put([multiCurr, subroot[1] + "M", depth])
        else:
            open_set.put([multiCurr, subroot[1] + "M", depth])
            open_set.put([addCurr, subroot[1] + "A", depth])

【问题讨论】:

    标签: python python-3.x performance search


    【解决方案1】:

    您不需要测试range(p, q + 1) 序列中的每个值。您只需要测试pq。如果它适用于最低和最高数字,它将适用于介于两者之间的所有值,因为问题已简化为乘法和加法。你真的只需要测试program(q)的进度,保持它低于s,直到你创建了最短的程序,使program(p)等于或高于r

    但是,对于呼吸优先搜索来说,这并不是一个真正的大问题。您的第二个示例需要测试 17.6 trillion 个可能的状态;最短的解决方案是 44 个字符长,因此呼吸优先搜索将探索 2 ** 44 个状态,准确地说是 17,592,186,044,416!即使使用像 C 这样的编译编程语言也需要很长时间才能使用这种搜索找到解决方案。相反,您可以使用一些数学来生成字符串。

    您可以计算此处使用int(math.log(s // q, m)) 所需的最大乘法次数,这是从q 开始时您可以与m 相乘并且仍低于s 的次数。你永远不能使用更多的乘法!使用math.ceil(math.log(r / p, m)),您可以找到使p 等于或高于r 的最小乘法数。要最小化程序长度,请选择这两个数字中的较低值。

    然后,在每个 M 乘法之前开始拟合 A 加法。将i 作为后面的M 字符数,然后将rs 除以m ** i。这些通知数字 a 添加到 pq 连同随后的乘法使其最接近 rs;与当前pq 的区别让您计算可以在此处插入以保持在[r, s] 范围内的A 字符的最小数量。对于p,向上取整,对于q,向下取整。

    对每个后续 M 操作重复此过程,每次都使用结果更新 pq 值:

    import math
    
    def problem3(s):
        a, m, p, q, r, s = map(int, s.split())
        p_mult = math.ceil(math.log(math.ceil(r / p), m))
        q_mult = int(math.log(s // q, m))
        mult = min(p_mult, q_mult)
        program = []
        for i in range(mult, -1, -1):
            p_additions = math.ceil((math.ceil(r / (m ** i)) - p) / a)
            q_additions = ((s // (m ** i)) - q) // a
            additions = min(p_additions, q_additions)
            program += [additions * 'A']
            if i:
                p, q = (p + (additions * a)) * m, (q + (additions * a)) * m
                program += ['M']
        return ''.join(program)
    

    这是一个封闭形式的解决方案,无需搜索。结果保证最短:

    >>> problem3("1 2 2 3 10 20")
    'AMM'
    >>> problem3("8 13 28 91 375383947 679472915")
    'AAAAAAMAAMAAAAAAAAAAAMAAAAAMAAAMAAAAMAAAAAAA'
    

    【讨论】:

      猜你喜欢
      • 2010-12-17
      • 2011-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-02
      • 1970-01-01
      • 2016-02-16
      • 1970-01-01
      相关资源
      最近更新 更多