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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

4回答

5562閲覧

計算量を少なくするアイデア

Looove

総合スコア11

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

2クリップ

投稿2017/12/04 01:42

編集2017/12/06 08:57

###前提・実現したいこと

処理速度を早くする方法を知りたいです。

36個の形が違う石を箱に詰めていきます。それぞれ1〜36の番号をつけます。
箱の大きさは一辺2mの立方体です。
まず、石2〜5個の組み合わせを考え、ある条件を満たしている組み合わせのみ配列に格納します。これがおおよそ800通り程あります。
その後、この800の組み合わせからさらに、5〜19個の組み合わせを考えます。この時1〜36の数字が必ず一つずつ入るような組み合わせを求めたいです。

###発生している問題・エラーメッセージ

計算量が膨大すぎて結果を出すのにあまりにも時間がかかる。

if k[1][0] == k[2][0]:この記述だと不完全なのはわかっていますが、どうかけばいいのかアイデアをいただきたいです。

###該当のソースコード

python

1import xlrd 2import os.path 3import numpy as np 4import itertools 5import sys 6import openpyxl 7 8xlfile = "結果.xlsx" 9if os.path.exists(xlfile): 10 xls = xlrd.open_workbook(xlfile) 11 sheet1 = xls.sheet_by_index(0) 12 nrows = sheet1.nrows 13 ncols = sheet1.ncols 14 data = np.zeros(ncols*nrows).reshape((nrows, ncols)) 15 surablist = [] 16 atusalist = [] 17 seibunlist = [] 18 taisekilist = [] 19 kekkalist = [] 20 kekkalist4 = [] 21 22 for r in range(0, nrows): 23 for c in range(0, ncols): 24 data[r,c] = sheet1.cell(r,c).value 25 26 for r in range(0, nrows): 27 surablist.append(data[r,0]) 28 atusalist.append(data[r,2]) 29 seibunlist.append(data[r,3]) 30 taisekilist.append(data[r,5]) 31 32 for i, _ in enumerate(surablist, 2): 33 if i == 6: 34 break 35 for j in itertools.combinations(surablist, r=i): 36 if i == 2: 37 n = int(j[0]-1) 38 m = int(j[1]-1) 39 if data[n,3] == data[m,3] and data[n,2] + data[m,2] <= 2.0 and data[n,5] + data[m,5] <=2.56: 40 41 # kekkalist.append(j) 42 pass 43 44 elif i == 3: 45 o = int(j[0]-1) 46 p = int(j[1]-1) 47 v = int(j[2]-1) 48 if data[o,3] == data[p,3] and data[o,3] == data[v,3] and data[p,3] == data[v,3] and data[o,2] + data[p,2] + data[v,2] <= 2.0 and data[o,5] + data[p,5] + data[v,5] <= 2.56: 49 # kekkalist.append(j) 50 pass 51 52 53 elif i == 4: 54 g = int(j[0]-1) 55 u = int(j[1]-1) 56 z = int(j[2]-1) 57 a = int(j[3]-1) 58 if data[g,3] == data[u,3] and data[g,3] == data[a,3] and data[g,3] == data[z,3] and data[u,3] == data[z,3] and data[a,3] == data[u,3] and data[z,3] == data[a,3] and data[g,2] + data[u,2] + data[z,2] + data[a,2] <= 2.0 and data[g,5] + data[u,5] + data[z,5] + data[a,5] <= 2.56: 59 kekkalist4.append(j) 60 61 else: 62 q = int(j[0]-1) 63 w = int(j[1]-1) 64 e = int(j[2]-1) 65 f = int(j[3]-1) 66 h = int(j[4]-1) 67 if data[q,3] == data[w,3] and data[q,3] == data[f,3] and data[q,3] == data[e,3] and data[q,3] == data[h,3] and data[w,3] == data[e,3] and data[f,3] == data[w,3] and data[h,3] == data[w,3] and data[e,3] == data[f,3] and data[e,3] == data[h,3] and data[f,3] == data[h,3] and data[q,2] + data[w,2] + data[e,2] + data[f,2] + data[h,2] <= 2.0 and data[q,5] + data[w,5] + data[e,5] + data[f,5] + data[h,5] <= 2.56: 68 kekkalist.append(j) 69 70 71 72 73 74 75 76z = 0 77a = 0 78b = 0 79c = 0 80d = 0 81e = 0 82f = 0 83g = 0 84h = 0 85j = 0 86l = 0 87m = 0 88n = 0 89o = 0 90p = 0 91q = 0 92r = 0 93s = 0 94t = 0 95u = 0 96v = 0 97w = 0 98x = 0 99ab=0 100ac=0 101ad=0 102ae=0 103af=0 104ag=0 105ah=0 106ai=0 107aj=0 108ak=0 109al=0 110am=0 111an=0 112ao=0 113 114for i, _ in enumerate(kekkalist4,9): 115 if i == 10: 116 break 117 118 for k in itertools.combinations(kekkalist4, r=i): 119 for y in range(0,9): 120 z += len(k[y]) 121 # if z == 43: 122 # print(k) 123 124 if y == 0: 125 z = 0 126 a = 0 127 b = 0 128 c = 0 129 d = 0 130 e = 0 131 f = 0 132 g = 0 133 h = 0 134 j = 0 135 l = 0 136 m = 0 137 n = 0 138 o = 0 139 p = 0 140 q = 0 141 r = 0 142 s = 0 143 t = 0 144 u = 0 145 v = 0 146 w = 0 147 x = 0 148 ab=0 149 ac=0 150 ad=0 151 ae=0 152 af=0 153 ag=0 154 ah=0 155 ai=0 156 aj=0 157 ak=0 158 al=0 159 am=0 160 an=0 161 ao=0 162 163 if k[y].count(1.0) == 1: 164 a += 1 165 if k[y].count(2.0) == 1: 166 b += 1 167 if k[y].count(3.0) == 1: 168 c += 1 169 if k[y].count(4.0) == 1: 170 d += 1 171 if k[y].count(5.0) == 1: 172 e += 1 173 if k[y].count(6.0) == 1: 174 f += 1 175 if k[y].count(7.0) == 1: 176 g += 1 177 if k[y].count(8.0) == 1: 178 h += 1 179 if k[y].count(9.0) == 1: 180 j += 1 181 if k[y].count(10.0) == 1: 182 l += 1 183 if k[y].count(11.0) == 1: 184 m += 1 185 if k[y].count(12.0) == 1: 186 n += 1 187 if k[y].count(13.0) == 1: 188 o += 1 189 if k[y].count(14.0) == 1: 190 p += 1 191 if k[y].count(15.0) == 1: 192 q += 1 193 if k[y].count(16.0) == 1: 194 r += 1 195 if k[y].count(17.0) == 1: 196 s += 1 197 if k[y].count(18.0) == 1: 198 t += 1 199 if k[y].count(19.0) == 1: 200 u += 1 201 if k[y].count(20.0) == 1: 202 v += 1 203 if k[y].count(21.0) == 1: 204 w += 1 205 if k[y].count(22.0) == 1: 206 x += 1 207 if k[y].count(23.0) == 1: 208 ab += 1 209 if k[y].count(24.0) == 1: 210 ac += 1 211 if k[y].count(25.0) == 1: 212 ad+= 1 213 if k[y].count(26.0) == 1: 214 ae += 1 215 if k[y].count(27.0) == 1: 216 af += 1 217 if k[y].count(28.0) == 1: 218 ag += 1 219 if k[y].count(29.0) == 1: 220 ah += 1 221 if k[y].count(30.0) == 1: 222 ai += 1 223 if k[y].count(31.0) == 1: 224 aj += 1 225 if k[y].count(32.0) == 1: 226 ak += 1 227 if k[y].count(33.0) == 1: 228 al += 1 229 if k[y].count(34.0) == 1: 230 am += 1 231 if k[y].count(35.0) == 1: 232 an += 1 233 if k[y].count(36.0) == 1: 234 ao += 1 235 if all([a,b,c,d,e,f,g,h,j,l,m,n,o,p,q,r,s,t,u,v,w,x,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an,ao]) == True: 236 print (k)

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

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

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

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

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

ozwk

2017/12/04 02:17

「重量がW[i]である石N個を容量Mの箱に収めるとき箱数が最小となる収め方を全て求めよ」って感じですかね
Looove

2017/12/04 02:25

そうです!まさにそのような感じです。
ozwk

2017/12/04 02:29

で、もっと条件が厳しくて、石は直方体で、箱は容積が決まっていて、さらに化学成分的に安定するように入れる必要があると
Looove

2017/12/04 02:31

はいその通りです。
ozwk

2017/12/04 03:40

でもコード見ると石のパラメータは厚さとsurab(?)と成分の3つしかないようですが。直方体+化学成分なら4つあるはずですよね?
Looove

2017/12/04 05:03

石の設定としては厚さ、長さ、化学成分、幅がありますが、幅と長さは全て条件を満たしているので省いています。またsurabは1~36の番号を示しています。
guest

回答4

0

36個の形が違う石を箱に詰めていきます
処理速度を早くする方法を知りたいです

  1. 要件を整理する
  2. 速い言語で書く
  3. 速いアルゴリズムで書く

まず、要件定義を詰めるだけで、結果的に速くなる場合があります。
「化学成分」という、重要そうなキーワードが質問文にないあたり、
質問者の方の中でも、整理しきれていないように感じます。

要件しだいで速くなるというのは、たとえば、要件が許容する範囲で、
整数化したり、グリッド化(マス目に当てはめ)したり、近似化することです。

次に、実行速度が速い言語で書くだけで、何十倍も速くなる場合があります。
C/C++、C#、Javaとかです。PythonやRubyなどの動的言語は遅い。

そして、速いアルゴリズムで書くことも大事です。
今回は**「ナップサック問題」っぽいので、「動的計画法(DP)」**などが向いています。


また、分かりやすさにも言及したいと思います。
質問文のサンプルコードが、非常に読みにくいです。
たとえば、横に長いIF文、縦に長いIF文(の列)とか……。

もしかしたら、多少速い書き方で、わざとそう書いたのかもしれません。
しかし、遅い言語で分かりにくく書くよりも、
速い言語で分かりやすく書いた方が、はるかに早くて楽です。

多少のオーバーヘッドは無視して、
まず分かりやすく書いて、次に速く書き直す方が、
開発速度も含めて総合的には、良い結果が出ることが多いです。


この問題、要件によっては、私なら**「遺伝的アルゴリズム(GA)」**で書くかも。
パフォーマンスだけ見れば、動的計画法に負けることもよくあるんですが、
とにかく分かりやすいから、複雑な問題になるほど、GAの方を選びます。

具体的にどう書くか、概要を言いますと、GA部分と評価部分を分けます。
評価部分はたとえば、GUIがない自動操作の「三次元テトリス」のイメージです。
上からガッチョンガッチョン石を落として、埋まったら密度とかでスコアを評価。

GAの方は、たとえば石の選び方を遺伝子に持ちます。
(配列)変数が36個あり、箱の番号が書いてあるとか。
そうして、評価AIの効率化と、GAの効率化を別々に進めます。

GAはDPより冗長になるかもしれませんが、実装しやすいし、
変更時に何を変更するか分かりやすいので、変更しやすいです。

たとえば、化学成分の相性を判定する場合でも、
GAモジュールの方は独立してるので、変更がないわけです。

それに、判定部分にDPを使うとか、併用することも可能です。
あるいは、評価部分にもGAを使うとか、多重で使うことも可能です。

実際の実用で使うプログラムなら、たとえば変な積み方をすると、
石の重さで割れるから、構造力学的に形状と重量も考慮するとか、
サンプルよりはるかに複雑になるし、仕様変更も生じます。

「化学成分」みたいな、隠れた仕様がまだ出てきそうなので、
複雑になるようなら、GAも選択肢としてアリだと思います。

投稿2017/12/04 19:43

LLman

総合スコア5592

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

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

0

ベストアンサー

石2〜5個の組み合わせを考え、ある条件を満たしている組み合わせのみ配列に格納します。

ある条件とは「全てが同一成分で厚さの合計が2[m]以下」でよいでしょうか?
であれば、同一成分でグループ化し、各グループ毎に2~5個の組み合わせを列挙したほうがよいです。
さらに各成分毎のグループ内の要素を厚さ順にソートしておけば、厚さ順に組合せ列挙走査する過程で2[m]を超えたら足切りできるので、全組合せを列挙する必要もなくなります。

その後、この800の組み合わせからさらに、5〜19個の組み合わせを考えます。

この部分に該当するソースがよく理解できなかったのですが、まずは石を足した合計が36個かの判定を加えることで走査数は減ると思われます。

投稿2017/12/04 09:28

can110

総合スコア38266

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

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

0

アルゴリズム的にはナップサック問題でよく用いられる動的計画法を使うのがよいかと思います。

計算時間を短縮したいのであれば、C言語で書き直すとそれだけで10分の1程度の実行時間になります。
この問題、あまりpythonは得意ではありません。


他にも

g = int(j[0]-1) u = int(j[1]-1)

のようなものを予めキャストしておくなどが考えられます。

投稿2017/12/04 04:06

編集2017/12/04 04:09
mkgrei

総合スコア8560

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

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

0

問題を小さくして考えて、それを一般化した方がよいかと思います。
一辺2mの立方体の中に石は全部収まるのでしょうか。
何をされたいのかがいまいちイメージできませんでした。

もし石が立方体からあふれるのであれば、ナップザック問題のような考え方をされるとよいのではないかと思います。

投稿2017/12/04 01:50

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

Looove

2017/12/04 01:53

言葉が足らず申し訳ありません。一辺2mの立方体はたくさんあります。ですができるだけ少ない箱数で36個の石を全て収めたいということです。
退会済みユーザー

退会済みユーザー

2017/12/04 02:12

実際の石の形まで考慮した計算をされようとしていますか? それとも立方体のパターンで近似されますか?パターンの数は限定されますか? このあたりの考慮によって計算のやりやすさは変わってきます。 最初の答えが yes の場合は計算は大変かと思います。 次の答えがどちらも yes であれば、解くのはそれほど難しくはないかもしれません。
Looove

2017/12/04 02:24

石の長さ、厚さ、幅、化学成分を考慮した計算をしようとしています。立方体のパターンで近似されません。
退会済みユーザー

退会済みユーザー

2017/12/04 03:34

聞いた感じですと、3Dモデルを作って物理演算をシミュレーションしてみるというのが案外手軽そうに思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問