조합 최적화로 벽 로직 풀기
Advent Calendar 15 일 기사 조합 최적화의 격차를 풀기
이게 뭐야
벽 로직을 파이썬에서 조합 최적화 모델을 만들어 풀어 라.
푸는 재미는 모델링을 고안하는 것입니다.
자신도 시도하고 싶은 사람은 아래를 참조하십시오.
문제
아래는 왼쪽이 문제이고 오른쪽이 대답입니다.
data
에 힌트의 수가 들어 있다고 합니다.파이썬
import pandas as pd
from itertools import product
from pulp import LpProblem, lpSum, lpDot, value
from ortoolpy import addvars, addbinvars
data = """\
4..1..
.4..2.
..2..2
1..1..
.1..1.
..3..2""".split()
변수 테이블
아래와 같은 변수 테이블을 작성합니다. 각 행의 변수는 0 또는 1을 취합니다.
변수의 값이 1이면 해당 행 해당 열의 질량이 검정색입니다.
"향"은 {0:왼쪽, 1:상, 2:오른쪽, 3:아래}입니다.
VDir
는 그 방향인가 어떤가, VLen
는 화살표의 길이입니다.행
열
향
VDir
VLen
0
0
0
0
v000001
v000145
1
0
0
1
v000002
v000146
...
...
...
...
...
...
파이썬
ni, nj = len(data), len(data[0])
mx = max(ni, nj)
a = pd.DataFrame([(i,j,k) for i,j,k in product(range(ni),
range(nj),range(4))], columns=list('行列向'))
a['VDir'] = addbinvars(len(a))
a['VLen'] = addvars(len(a))
a[:2]
수리 모델을 만들어 풀다
변수 테이블을 만들었으므로 벽 논리를 해결할 수 있도록 제약 조건을 추가하고 수리 모델을 만들고 해결합니다.
파이썬
drc = [(-1, 0, 0), (0, -1, 1), (0, 1, 2), (1, 0, 3)]
m = LpProblem()
for i,j in product(range(ni), range(nj)):
b = a[(a.行==i)&(a.列==j)]
if data[i][j].isdigit():
m += lpSum(a[(a.行==i+y)&(a.列==j+x)&(a.向==k)].VLen
for y,x,k in drc) == int(data[i][j]) # (1)
m += lpSum(b.VLen) == 0 # (1)
continue
m += lpSum(b.VDir) == 1 # (2)
for y,x,k in drc:
r = b[b.向==k].iloc[0]
m += r.VLen <= mx * r.VDir # (3)
m += r.VLen <= r.VDir + lpSum(
a[(a.行==i+y)&(a.列==j+x)&(a.向==k)].VLen) # (3)
m.solve()
결과 표시
파이썬
a['Val'] = a.VDir.apply(value)
print('\n'.join(''.join(' '+(data[i][j] if data[i][j].isdigit()
else '↑←→↓'[int(value(lpDot([0,1,2,3],a[(a.行==i)&(a.列==j)].Val)))])
for j in range(ni)) for i in range(nj)))
>>>
4 → → 1 → ↑
↓ 4 → → 2 ↑
↓ ↓ 2 → ↓ 2
1 ↓ ↓ 1 ↓ ↑
↓ 1 → ↓ 1 ↑
← ← 3 → ↓ 2
풀리고 있는지 확인할 수 있습니다.
이상
Reference
이 문제에 관하여(조합 최적화로 벽 로직 풀기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/SaitoTsutomu/items/24742740571bc122e2b8텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)