优化蛮力数字求解器python的建议

时间:2018-08-02 17:22:36

标签: python algorithm optimization brute-force

我知道其他一些类似的线程,但是我不确定如何将其应用于我的示例。

我正在尝试通过蛮力算法来攻击倒数游戏。这是我对此类事情的首次尝试,那么有关如何加快该过程的任何提示?

我正在测试在给定初始数字的情况下答案无法解决的情况。最终将与完整游戏的tkinter界面配对。

结构应如下所示,在这里我们尝试abcdef的每个顺序以及op1-5的每个操作组合

from datetime import datetime
import itertools
import math

starttime = datetime.now()
def permutationG(input, s):
    if len(s) == len(input): yield s
    for i in input:
        if i in s: continue
        s=s+i
        for x in permutationG(input, s): yield x
        s=s[:-1]
def op(operator, number1,number2):
    string=str(number1)+str(operator)+str(number2)
    return eval(string)

a=11
b=10
c=9
d=8
e=7
f=6

targetnumber = 101234

listofnumbers = ['a','b','c','d','e','f']
listprep = ['+','-','*','/']
stringofnumbers = ''.join(str(e) for e in listofnumbers)


numberlocations =[]

for item in permutationG(listofnumbers,''):
    numberlocations.append(item)
numberlocations = set(numberlocations)

myarray = itertools.combinations_with_replacement(listprep, 5)
operatorlist = []
for item in myarray:
    #for all different numbers find the different permutations
    temp = list(itertools.permutations(item))
    operatorlist.extend(temp)
#remove duplicates
finaloplist = list(set(operatorlist))

dist=[math.inf]
currentclosestnumber = 0
count=0
looptime=datetime.now()
print('Starting Loop')

for item in numberlocations:
    for ops in finaloplist:
        initial_value = op(ops[0],item[0],item[1])
        for i in range(2,len(item)):
            intcheck2 = int(initial_value) - initial_value
            if initial_value != targetnumber and initial_value >= 0 and intcheck2 == 0:
                newvalue = op(ops[i-1], initial_value, item[i])
            else:
                break
            initial_value = newvalue
        attempt = initial_value
        intcheck = int(attempt) - attempt
        distance = targetnumber - initial_value
        if abs(distance) < abs(dist[0]) and intcheck == 0:
            currentclosestnumber = attempt
            dist[0]=distance
            print(attempt)
        if targetnumber == attempt:
            break
    if targetnumber == attempt:
        break

endtime = datetime.now()
stringtime= endtime-starttime
#print('Loops:    ', count)

if targetnumber == attempt:
    print('FOUNDIT!! Target Number = %s     Closest Number = %s        Time Elapsed = %s' %(targetnumber, currentclosestnumber, stringtime))
elif targetnumber!=attempt:
    print('Heres how close: Target Number = %s     Closest Number = %s        Time Elapsed = %s' %(targetnumber, currentclosestnumber, stringtime))

这将输出大约一分半钟的时间。

另一个问题是由于我使用的方法(使用eval字符串操作),我不知道在打印时要显示括号在最终公式中的位置,也不知道如何将eval放入拉链的末尾。显示数字而不是字母。

真的很感谢任何指导。


注意:我已使用最新版本的代码对帖子进行了编辑。这样可以将计算时间从1:30减少到0:45。主要的变化是,我为每个顺序操作创建了一个for循环,而不是一长串计算,并使用了if语句来确保如果当前值是负数或十进制数,它将中断。

这大大减少了所需的计算次数。

1 个答案:

答案 0 :(得分:0)

这是一个较慢的版本,但没有错误。

我没有时间尝试进行优化,但是我的想法是,大多数问题在于在拆分子集时创建/销毁垃圾。

如果我真的希望这样快,那么我认为您可以使用动态编程方法。

def subset_splits (a_list):
    if 0 == len(a_list):
        yield ([], [])
    else:
        for sublist1, sublist2 in subset_splits(a_list[1:]):
            yield ([a_list[0]] + sublist1, sublist2)
            yield ([a_list[0]] + sublist2, sublist1)

def reachable (numbers):
    if 1 == len(numbers):
        yield (numbers[0], numbers[0])
    else:
        for list1, list2 in subset_splits(numbers):
            if 0 == len(list2):
                continue
            for x1, expr1 in reachable(list1):
                for x2, expr2 in reachable(list2):
                    yield x1+x2, (expr1, '+', expr2)
                    yield x1*x2, (expr1, '*', expr2)
                    yield x1-x2, (expr1, '-', expr2)
                    yield x2-x1, (expr2, '-', expr1)
                    if 0 != x2:
                        yield x1/x2, (expr1, '/', expr2)
                    if 0 != x1:
                        yield x2/x1, (expr2, '/', expr1)

numbers = [1, 2, 3, 4, 5, 6]
target = 10000

best = numbers[0]
if best == target:
    print(("Answer: ", numbers[0], numbers[0]))
else:
    print(("Best: ", numbers[0], numbers[0]))
    done = False;
    for s, t in subset_splits(numbers):
        if done:
            break

        for x, expr in reachable(s):
            if x == target:
                print(("Answer: ", x, expr))
                done = True
                break
            elif abs(target-x) < abs(target-best):
                print(("Best: ", x, expr))
                best = x

        if done:
            break


        for x, expr in reachable(t):
            if x == target:
                print(("Answer: ", x, expr))
                done = True
                break
            elif abs(target-x) < abs(best-x):
                print(("Best: ", x, expr))
                best = x