조합 최적화로 빌딩 해결

Advent Calendar 19 일 기사 조합 최적화로 몇 코로 풀기
Advent Calendar 21 일 기사 조합 최적화로 혼자 해줘.

이게 뭐야



빌딩을 Python에서 조합 최적화 모델을 만들어 풀어 라.
푸는 재미는 모델링을 고안하는 것입니다.

자신도 시도하고 싶은 사람은 아래를 참조하십시오.
  • 스도쿠를 통해 조합 최적화를 배우자.

  • 문제


  • 각 숫자는 그 매스에 세워지는 빌의 높이를 나타냅니다.
  • 각 횡행에 같은 숫자는 들어가지 않습니다.
  • 각 세로 열에 같은 숫자가 들어 있지 않습니다.
  • 반면의 외측의 숫자는 그 숫자의 쓰여진 장소로부터 반면을 바라볼 때 같은 횡행(또는 세로열)으로 보이는 빌딩의 수를 나타냅니다.

  • 아래는 왼쪽이 문제이고 오른쪽이 대답입니다.



    입력 파라미터


    data 에 힌트가 들어 있다고 합니다.

    파이썬
    import numpy as np
    from pulp import LpProblem, lpSum, lpDot, value
    from ortoolpy import addvar, addvars, addbinvars
    data = """\
       33  
     ..... 
     .....5
    2.....1
    3.....3
     .....2
      5 13 """.splitlines()
    n = len(data)-2
    

    파이썬으로 풀기



    수리 모델을 만들고 풀어 봅시다.

    변수


  • v: 각 위치가 어느 높이인지 (1)
  • r: 각 위치의 높이 (2)
  • u : 각 방향별 숫자가 있는 각 열에 대해 (3)

  • 제약


  • $v_{ij}$는 하나의 높이 만 (4)
  • r을 v로 표현 (5)
  • 세로 또는 가로에 같은 높이가 없어야 함 (6)
  • 상하좌우에서 보았을 때 u의 합계가 「숫자-1」(즉, 높아질 때 u==1로 합니다) (7)

  • 파이썬
    m = LpProblem()
    v = np.array(addbinvars(n, n, n)) # (1)
    r = np.array(addvars(n, n)) # (2)
    def add(m, c, p, q, y, x):
        if not c.isdigit():
            return
        k = int(c)
        u = addvars(n-1) # (3)
        m += lpSum(u) == k - 1 # (7)
        vmx = r[p,q]
        for i in range(1,n):
            vnx = r[p + y*i][q + x*i]
            m += vmx + n * u[i-1] >= vnx + 1 # (7)
            m += vmx + 1 <= vnx + n - n * u[i-1] # (7)
            vtm = addvar()
            m += vmx <= vtm # (7)
            m += vnx <= vtm # (7)
            vmx = vtm
        m += vmx <= n # (7)
    for i in range(n):
        for j in range(n):
            m += lpSum(v[i,j,:]) == 1 # (4)
            m += lpDot(range(n), v[i,j]) + 1 == r[i,j] # (5)
            m += lpSum(v[i,:,j]) == 1 # (6)
            m += lpSum(v[:,i,j]) == 1 # (6)
        add(m, data[i+1][  0],   i,   0,  0,  1)
        add(m, data[i+1][n+1],   i, n-1,  0, -1)
        add(m, data[  0][i+1],   0,   i,  1,  0)
        add(m, data[n+1][i+1], n-1,   i, -1,  0)
    m.solve()
    

    결과 표시



    파이썬
    print(np.vectorize(value)(r).astype(int))
    >>>
    [[2 5 1 3 4]
     [5 4 3 2 1]
     [4 3 2 1 5]
     [1 2 5 4 3]
     [3 1 4 5 2]]
    

    풀리고 있는지 확인할 수 있습니다.

    이상

    좋은 웹페이지 즐겨찾기