1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

組合せ最適化でのりのりを解く

Last updated at Posted at 2017-12-07

Advent Calendar 7日目の記事 組合せ最適化で因子の部屋を解く
Advent Calendar 9日目の記事 組合せ最適化でチョコナを解く

これなに

のりのりを、Pythonで組合せ最適化モデルを作って解きます。
解く楽しみは、モデル化を工夫することになります。

自分でも試してみたい人は、下記を参考にしてください。

問題

  • 盤面のいくつかのマスを黒くぬります。
  • 黒マスは必ずタテかヨコにちょうど2つだけぬります。
  • 太線で区切られた各部分には、黒マスが2つずつ入ります。

左が問題で、右が答えです。

Pythonでは、data(部屋のグループ)を使うことにします。

python
import pandas as pd, matplotlib.pyplot as plt
from pulp import LpProblem, lpSum, value
from ortoolpy import addbinvars
data = """\
ABBBC
ADDBC
EDBBB
EEEEE
EEEEE""".splitlines()

変数表

下記のような変数表を作成します。各行の変数は0または1をとります。
変数の値が1ならば、該当行 該当列のマスが黒になります。

Var
0 0 0 A v000001
1 0 1 B v000002
... ... ... ... ...
python
ni, nj = len(data), len(data[0])
a = pd.DataFrame([(i,j,data[i][j]) for i in range(ni)
    for j in range(nj)], columns=list('行列字'))
a['Var'] = addbinvars(len(a))
a[:2]

数理モデルを作り解く

変数表ができたので、のりのりの解になるように、制約条件を追加し数理モデルを作成し、解きましょう。

  • あるマスが黒なら、その上下左右の黒の数はちょうど1となる。これは、下記の2つの式で表現できます(Mは十分大きな数)。
    • 上下左右の黒の数 >= 該当マスの黒の数
    • 上下左右の黒の数 <= 1 + M*(1-該当マスの黒の数)
  • 各グループ内の黒の数はちょうど2。
python
m = LpProblem()
for _,r in a.iterrows():
    e = lpSum(a.query(f'abs(行-{r.})+abs(列-{r.})==1').Var)
    m += e >= r.Var
    m += e <= 1+(len(e)-1)*(1-r.Var)
for g,v in a.groupby(''):
    m += lpSum(v.Var) == 2
m.solve()

結果の表示

python
a['Val'] = a.Var.apply(value)
plt.imshow((a.Val<0.5).values.reshape(ni,nj), cmap='gray', interpolation='none')
plt.show()

image.png

解けていることが確認できます。

以上

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?