質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
最適化

最適化とはメソッドやデザインの最適な処理方法を選択することです。パフォーマンスの向上を目指す為に行われます。プログラミングにおける最適化は、アルゴリズムのスピードアップや、要求されるリソースを減らすことなどを指します。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

909閲覧

ナンプレを線形計画法で解く際のロジックについて

eggpol

総合スコア60

最適化

最適化とはメソッドやデザインの最適な処理方法を選択することです。パフォーマンスの向上を目指す為に行われます。プログラミングにおける最適化は、アルゴリズムのスピードアップや、要求されるリソースを減らすことなどを指します。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2019/06/25 09:15

編集2019/06/25 09:29

こちらのサイトを参考にナンバープレイス(通称ナンプレ)を線形計画法で解こうと考えています。
まず整数計画法のモデルを作るためにナンプレのルールを以下とします。

ルール 1. 横一列に同じ数字はこない 2. 縦一列に同じ数字はこない 3. 3x3 のブロック内に同じ数字はこない

モデルに関しては

0-1 整数計画 目的関数は不要 としています
import pulp from itertools import product from pprint import pprint def main(): # 問題表(0が空白マス) Board = [[0, 0, 0, 0, 4, 0, 6, 0, 0], [7, 5, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 0, 0], [0, 0, 9, 0, 0, 1, 0, 3, 0], [0, 0, 6, 0, 0, 0, 4, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 3, 7, 0, 0, 5], [2, 0, 4, 0, 6, 0, 0, 0, 0]] # 問題の宣言 problem = pulp.LpProblem() # 定数の宣言 line = list(range(9)) # 変数の宣言 x = [[[pulp.LpVariable(f'x{i}{j}{k}', cat='Binary') for k in line] for j in line] for i in line] # 目的関数 # 今回はなし # 制約条件 # すでに埋まっているマスの情報を入力 for i, j in product(line, line): if Board[i][j] > 0: problem += x[i][j][Board[i][j]-1] == 1 # 数独のルールに合うように制約を追加 for j, k in product(line, line): #print(i,j,k) problem += pulp.lpSum(x[i][j][k] for i in line) == 1 for k, i in product(line, line): print(i,j,k) problem += pulp.lpSum(x[i][j][k] for j in line) == 1 for i, j in product(line, line): #print(i,j,k) problem += pulp.lpSum(x[i][j][k] for k in line) == 1 three_block = [[ii, ii+1, ii+2] for ii in [0, 3, 6]] for a, b in product(three_block, three_block): for k in line: problem += pulp.lpSum(x[i][j][k] for i in a for j in b) == 1 # ソルバーの実行 # problem.solve(pulp.GUROBI()) problem.solve() # 結果の表示 print('Result') for i, j, k in product(line, line, line): if x[i][j][k].value() == 1: Board[i][j] = k + 1 pprint(Board) if __name__ == '__main__': main()

参考
イメージ説明

わからないこと

ライブラリに投げているのでproblem.solve()の中でどのような動きが起きているかわからないです

自分の考えとしては
貪欲法を用いて総当たりで最悪9!*9通りを総当たりして枝狩り?を行う。途中で行けそうでないなら
やめればもう少し少ない計算量で行けるのかなと思いました。(そもそも総当たりが9!*9通りであってるのかな・・・)
どうやって最適解を見つけているのでしょうか

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiitoi

2019/06/25 11:22

maisumakun さんのご回答の通り、実用上は自前実装ではなく、ソルバーを使うのが推奨されます。 ソルバーは高度に最適化されているのですが、元となるアルゴリズムが気になるのであれば、「分枝限定法」で調べてみるとよいでしょう。
eggpol

2019/06/26 02:09 編集

なるほど、「分技限定法」を調べてみます。ありがとうございました。
guest

回答2

0

ベストアンサー

ライブラリに投げているのでproblem.solve()の中でどのような動きが起きているかわからないです

それを考えなくて済むのがソルバーに任せるメリットだと思うのですが、どうでしょうか?

投稿2019/06/25 09:31

maisumakun

総合スコア145184

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

調べるさいの道標として回答します.(CBC のソースコードを見ていないので間違っていたらすみません).

混合整数計画ソルバーとして PuLP から Cbc (Coin-or branch and cut) を呼び出しているので problem.solve() でどのようなアルゴリズムが使用されているのかは Cbc を調べる必要があります.CBC User Guide には 分枝切除法(branch and cut method) をメインで使用していると書いているので「どのような動きをしているのか」を知る手がかりとして 分枝切除法 を調べるのをオススメします.ただし,一般に混合整数計画ソルバーにはいくつかのヒューリスティック(精度保証の無いアルゴリズム)を合わせて使用している場合があるので,problem.solve() を詳細に調べるときにはソースコードと CBC User Guide 等を参照する必要があると思います.

投稿2019/09/05 17:16

pqwm

総合スコア29

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問