简体   繁体   中英

find longest consequence of numbers so adjacents are factors or multiples

There is a puzzle to find the longest chain of numbers from 1 to 100 so that each next number should be multiple or factor for previous one. Each number can be taken once. I'm bad at programming but it was very interesting for me and I spent few hours with it.
I'm wondering how this my code could be made more effective. Now it can solve for only around 20 numbers in reasonable time. I suppose a lot of time is spent for 2 list copy operations and.pop(i) operation. Thank you. ps This is not homework.

Output for numbers=10 is [4, 8, 1, 5, 10, 2, 6, 3, 9]

qty = 100
max_length = 0
max = []

def main():
    numbers = list(range(1, qty + 1))
    solve([], numbers, 0)
    print(max)

def check_result(result):
    global qty, max_length, max
    if len(result) > max_length:
        max = result
        max_length = len(result)   

def solve(bufer, left, index):
    if index == qty:
        check_result(bufer)

    for i in range(len(left)):
        left_c = left.copy()
        bufer_c = bufer.copy()
        next = left_c.pop(i)

        if index == 0 or next % bufer_c[index - 1] == 0 or bufer_c[index - 1] % next == 0:
            bufer_c.append(next)
            solve(bufer_c, left_c, index + 1)
        else:
            check_result(bufer_c)

if __name__ == "__main__":
    main()

No deep insights here, just a few optimizations - it gets up to n = 35 in about a minute. The current method is essentially already a graph search, so finding the longest path efficiently is going to be difficult/impossible.

qty=35
max_length = 0
max = []
nr = 0

# precompute factors
factors = [[q for q in range(2, p) if p % q == 0] for p in range(1, qty+1)]

def main():
    numbers = list(range(1, qty + 1))
    left = [True] * qty
    left[0] = False
    solve([1], left, 1)
    print(max)

def check_result(result):
    global qty, max_length, max, nr
    if len(result) > max_length:
        nr += 1
        max = result.copy()
        max_length = len(result)   

def solve(bufer, left, index):
    global max
    if index > max_length:
        check_result(bufer)

    # do the multiples first 
    mult = bufer[index-1]*2
    while mult <= qty:
        if left[mult-1]:
            left[mult-1] = False
            bufer.append(mult)
            solve(bufer, left, index+1)
            bufer.pop()
            left[mult-1] = True
        mult += bufer[index-1]
    
    # then the factors
    for factor in factors[bufer[index-1] - 1]:
        if left[factor-1]:
            left[factor-1] = False
            bufer.append(factor)
            solve(bufer, left, index+1)
            bufer.pop()
            left[factor-1] = True

The optimizations are to only check the multiples and factors of the previous element and avoid copying lists. The list of numbers left is now a lookup table. I also fixed the starting element to be 1 - once the chain to the 'right' of 1 has been found, you can find the chain to the 'left' using the remaining numbers (I didn't implement this).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM