0
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 3 years have passed since last update.

NetworkXのbipartite(2部マッチング)でドラクエウォークのアイテムをマッチングする

Posted at

「問題解決力を鍛える!アルゴリズムとデータ構造」という本で「何人かの男性と女性とがいて,ペアになってもよいという2人の間には辺が張られているものとします.できるだけ多くのペアを作ろうとしたときに,最大で何組のペアを作ることができるでしょうか」という、いわゆる二部マッチング問題が紹介されていて、これは私がはまっているドラクエウォークのアイテム組み合わせに使えるんじゃないかと思った。

PythonではNetworkXというライブラリに2部マッチングが含まれているので、これで試してみようと思う。u++の備忘録を参考にした。

Google Colaboratoryでは特に追加インストールすることなく試すことができた。

import networkx
from networkx.algorithms import bipartite
import matplotlib.pyplot as plt

扱うデータと、重みづけ関数を下記のように定義しておく。ドラクエウォークは4人パーティだが簡単のため2人とし、片方に打撃系、片方に呪文の能力を高めたいという場合を想定している。メンバーが欲しいと思っている属性が武器に備わっていれば重みが加算される。

members = [
        ["ヒャド属性とくぎダメージ","物質系への耐性"],
        ["ヒャド属性じゅもんダメージ"],
]
arms = [
        {"name":"ガイアーラのよろい上","ヒャド属性とくぎダメージ":5},
        {"name":"フォースコート上","ヒャド属性とくぎダメージ":1},
        {"name":"蒼竜のよろい上","ヒャド属性とくぎダメージ":3},
        {"name":"書聖のはおり","ヒャド属性じゅもんダメージ":3,"物質系への耐性":5},
        {"name":"アリアハンの服上","ドラゴン系への耐性":1,"スライム系への耐性":3},
        {"name":"光のよろい","ドラゴン系への耐性":5},
]

def omomi(member,arm):
  val = 0
  for j in members[member]:
    if j in arms[arm-len(members)]:
      val = val + arms[arm-len(members)][j]
  return val

ノード0~1をメンバー、ノード2~7を武器ということにしてノードの追加、エッジの追加(同時に重みづけ)を行い、max_weight_matchingで最大マッチングを行う。

members_size = len(members)
arms_size = len(arms)

member_group = range(members_size)  # 0~1
arm_group = range(members_size,arms_size+members_size) # 2~7

g = networkx.Graph()
g.add_nodes_from(job_group, bipartite=1)
g.add_nodes_from(arm_group, bipartite=0)

for i in job_group:
  for j in arm_group:
    g.add_edge(i,j,weight=omomi(i,j))

d = networkx.max_weight_matching(g)

ここから先は描画。ノードの表示位置を適当に決め、最大マッチングに含まれていないエッジは削除する。

pos = {}
for i in job_group:
  pos[i] = (1,i)
for j in arm_group:
  pos[j] = (2,j-jobs_size)

for (i, j) in list(g.edges()):
    if (i, j) not in d:
        if (j, i) not in d:
            g.remove_edge(i,j)

networkx.draw_networkx(g,pos)
networkx.draw_networkx_edges(g,pos)
plt.show()

出力したグラフがこちら。1人目(ノード0)はガイアーラのよろい(ノード2)、2人目(ノード1)は書聖のはおり(ノード5)を選んでおり、想定とも合っている。

bipartite.png

ということで、NetworkXを使ってお手軽に二部マッチングを実装できた。重み付けだけ考えれば、あとは全部やってくれるというところがいい。

0
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
0
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?