KenKen puzzle addends: REDUX A (corrected) non-recursive algorithm

后端 未结 9 1664
眼角桃花
眼角桃花 2021-01-03 05:24

This question relates to those parts of the KenKen Latin Square puzzles which ask you to find all possible combinations of ncells numbers with values x such that 1 <= x &

9条回答
  •  -上瘾入骨i
    2021-01-03 05:54

    First of all, I'd use variable names that mean something, so that the code gets comprehensible. Then, after I understood the problem, it's clearly a recursive problem, as once you have chosen one number, the question of finding the possible values for the rest of the squares are exactly the same problem, but with different values in.

    So I would do it like this:

    from __future__ import division
    from math import ceil
    
    def make_combos(max_val,target_sum,n_cells):
        combos = []
        # The highest possible value of the next cell is whatever is 
        # largest of the max_val, or the target_sum minus the number 
        # of remaining cells (as you can't enter 0).
        highest = min(max_val, target_sum - n_cells + 1)
        # The lowest is the lowest number you can have that will add upp to 
        # target_sum if you multiply it with n_cells.
        lowest = int(ceil(target_sum/n_cells))
        for x in range(highest, lowest-1, -1):
            if n_cells == 1: # This is the last cell, no more recursion.
                combos.append((x,))
                break
            # Recurse to get the next cell:
            # Set the max to x (or we'll get duplicates like
            # (6,3,2,1) and (6,2,3,1), which is pointless.
            # Reduce the target_sum with x to keep the sum correct.
            # Reduce the number of cells with 1.
            for combo in make_combos(x, target_sum-x, n_cells-1):
                combos.append((x,)+combo)
        return combos
    
    if __name__ == '__main__':
        import pprint
        # And by using pprint the output gets easier to read
        pprint.pprint(make_combos( 6,12,4))
    

    I also notice that your solution still seems buggy. For the values max_val=8, target_sum=20 and n_cells=5 your code doesn't find the solution (8,6,4,1,1,), as an example. I'm not sure if that means I've missed a rule in this or not, but as I understand the rules that should be a valid option.

    Here's a version using generators, It saves a couple of lines, and memory if the values are really big, but as recursion, generators can be tricky to "get".

    from __future__ import division
    from math import ceil
    
    def make_combos(max_val,target_sum,n_cells):
        highest = min(max_val, target_sum - n_cells + 1)
        lowest = int(ceil(target_sum/n_cells))
        for x in xrange(highest, lowest-1, -1):
            if n_cells == 1:
                yield (x,)
                break
            for combo in make_combos(x, target_sum-x, n_cells-1):
                yield (x,)+combo
    
    if __name__ == '__main__':
        import pprint
        pprint.pprint(list(make_combos( 6,12,4)))
    

提交回复
热议问题