縦横のラベルの数から図の再現ができないか?の確認ロジック3

■樹形図のロジックの考え方。
前回からの続き。樹形図のようなものを考えて、1つずつ確認していくイメージで作っていく。
図にすると下のような感じ。

階層が図の行部分にあたる。1行目(1階層)がOKなら次の行を確認。2行目(2階層)がOKなら3行目を確認。3行目(3階層)がNGなら、同じ階層の次のものをチェック。この流れで確認していき、最後まで条件に合うものを出力する。該当するものが無ければ階層を上がって次のものをチェック。

簡単な下のサンプルで考える。縦と横で[1, 3, 2, 4], [3, 2, 2, 3]との数字が与えられていて、それを満たす図は何かを調べる。


これを確認するコードが下のもの。チェック部分とか固定の数を入れたハードなコーディングになっているけど、とりあえず試しで。

import itertools
import numpy


def checkResult(target):
    columnlist = [1, 3, 2, 4]
    a = 0
    b = 0
    c = 0
    d = 0
    for i in target:
        a = a + i[0]
        b = b + i[1]
        c = c + i[2]
        d = d + i[3]
    if a <= columnlist[0]:
        if b <= columnlist[1]:
            if c <= columnlist[2]:
                if d <= columnlist[3]:
                    return True
    return False


def checkline(parent, childrenList, columnlist, depth):
    list = parent

    if depth == 3:
        for child in childrenList:
            list.append(child)
            result = checkResult(list)
            if result == True:
                print(list)
            del list[len(list) - 1]
        return list

    for child in childrenList:
        list.append(child)
        result = checkResult(list)
        if result == True:
            depth = depth + 1
            checkline(list, makeCombination(4, columnlist[depth]), columnlist, depth)
            depth = depth - 1
        del list[len(list) - 1]

    return parent

def makeCombination(total, combNum):
    result = []
    list = range(total)
    for comb in itertools.combinations(list, combNum):
        list2 = numpy.zeros(total)
        if len(list) > 0:
            for n in comb:
                list2[n] = 1
        result.append(list2.tolist())
    return result


rowlist = [1, 3, 2, 4]
columnlist = [3, 2, 2, 3]
start = []
list = [0, 0, 0, 0]
start.append(list)
d = makeCombination(4, 3)
c = checkline(start, d, columnlist, 0)

この実行結果が下のもの。

この1行が図を表し、8つのものが条件に合うことが分かった。
この数字をExcelで再現すると、下のようになる。それぞれ縦横の合計数が条件に合っている。

考え方としてはこれでできそう。もう少しコードを一般化した上で、前の9×9の図で試してみる。