「Pythonではじめるアルゴリズム入門」という本の幅優先探索や深さ優先探索について書かれている章の
理解度チェック問題として以下のような問題と解答が掲載されていました。
しかし、解答コードに誤りがあるように思えるので自分でコードを書いたのですが正しいでしょうか?
問題:
都道府県の人口を組み合わせて1千万人に近い組み合わせとその人口を求めよ。
本に載っている解答:
Python
1# 近づける値 2goal = 10000000 3 4# 各都道府県の人口 5pref = [ 6 5381733, 1308265, 1279594, 2333899, 1023119, 1123891, 1914039, 7 2916976, 1974255, 1973115, 7266534, 6222666, 13515271, 9126214, 8 2304264, 1066328, 1154008, 786740, 834930, 2098804, 2031903, 9 3700305, 7483128, 1815865, 1412916, 2610353, 8839469, 5534800, 10 1364316, 963579, 573441, 694352, 1921525, 2843990, 1404729, 11 755733, 976263, 1385262, 728276, 5101556, 832832, 1377187, 12 1786170, 1166338, 1104069, 1648177, 1433566 13] 14 15min_total = 0 16def search(total, pos): 17 global min_total 18 if pos >= len(pref): 19 return 20 if total < goal: 21 if abs(goal - (total + pref[pos])) < abs(goal - min_total): 22 min_total = total + pref[pos] 23 search(total + pref[pos], pos + 1) 24 search(total, pos + 1) 25 26search(0, 0) 27print(min_total) #10001495 28
このコードだと答えは10001495となるのですが、
if abs(goal - (total + pref[pos])) < abs(goal - min_total):
で探索されるべきところが間違って枝刈りされているように見えます。
例えば
goal = 10
pref = [3,4,5,1,1,5]
だと、答えは10のはずが、12と明らかに間違った答が出るのですが
[3,4,5]でmin_totalが一度12になったらその後は[1]単体などは
if abs(goal - (total + pref[pos])) < abs(goal - min_total)
ではじかれて探索されなくなっているように見えます。
そこで次の様に書きました。
Python
1# 近づける値 2goal = 10000000 3 4# 各都道府県の人口 5pref = [ 6 5381733, 1308265, 1279594, 2333899, 1023119, 1123891, 1914039, 7 2916976, 1974255, 1973115, 7266534, 6222666, 13515271, 9126214, 8 2304264, 1066328, 1154008, 786740, 834930, 2098804, 2031903, 9 3700305, 7483128, 1815865, 1412916, 2610353, 8839469, 5534800, 10 1364316, 963579, 573441, 694352, 1921525, 2843990, 1404729, 11 755733, 976263, 1385262, 728276, 5101556, 832832, 1377187, 12 1786170, 1166338, 1104069, 1648177, 1433566 13] 14 15total_temp = float('inf') 16 17#total:合計 pos:探索ポジション l:探索ルートを入れるリスト pre:1つ前のtotal 18def search(total, pos, l, pre): 19 global total_temp 20 21 if total >= goal or pos >= len(pref): 22 a = abs(total - goal) 23 b = abs(pre - goal) 24 25 #preの方がgoalに近い場合 26 if a > b: 27 if b < abs(goal - total_temp): 28 total_temp = pre 29 print(total_temp,l[:-1] ) 30 #totalの方がgoalに近い場合 31 else: 32 if a < abs(goal - total_temp): 33 total_temp = total 34 print(total_temp, l) 35 return 36 37 #total < goal 38 else: 39 l1 = l.copy() 40 l1.append(pref[pos]) 41 search(total + pref[pos], pos + 1, l1, total) 42 search(total, pos + 1, l, total) 43 44search(0, 0, [], 0) 45print(total_temp)
これだと答えがぴったり
10000000
で組み合わせが
[1308265, 2333899, 786740, 2031903, 573441, 755733, 832832, 1377187]
と出たのですが、このコードで合っているでしょうか?
またもっと効率の良いアルゴリズムなどはあるでしょうか?
回答5件
あなたの回答
tips
プレビュー