paizaã®åé¡ã§15ããºã«ã解ãããã°ã©ã ãæ¸ãã¾ãã
ä¸ããããé
ç½®ãã§ããã ãå°ãªãã¹ã©ã¤ãåæ°ã§è§£ãåé¡ã§ã(å®è¡æéæéå¶éãã)
15ããºã«
1ãã15ã®ããã«ã4ããã4ã®æ£æ¹å½¢ã«é
ç½®ããã¦ãã¦ãããã«ãã¹ã©ã¤ãããã¦ãã£ã¦1ãã15ã¾ã§ãé çªã«ä¸¦ã¶ããã«ãããã®ã§ã
File:15-puzzle.svg - Wikimedia Commons
åããåæ°ãå¤ããªã£ã¦ããããªããç°¡åã«è§£ããæ¹æ³ãããã¿ãããªã®ã§äººéã¯ãã£ã¡ã使ã£ãã»ããããã§ããã
解ãæ¹
ããºã«ç³»ã®åé¡ã¯ã ããã幅優先探索ã深さ優先探索ã§è§£ãã¾ã
ç¥èã¨ãã¦ã¯ç¥ã£ã¦ãã¾ãããèªåã§æ¸ãããã¨ã¯ãªãã£ãã®ã§ãä»åã¯幅優先探索ã最良優先探索ãA*探索ã双方向探索ããããæ¸ãã¦ã¿ã¾ãã
ãã®è¾ºã®ã¢ã«ã´ãªãºã ã®èª¬æã¯ä»¥ä¸ã®è¨äºãè¿·è·¯ã®æ¢ç´¢ã®ã¢ãã¡ã¼ã·ã§ã³ã§è¡¨ããã¦ããããã¦ããããããããããã¾ãã
ä»åã®åé¡ã§ã¯èªåã®ã³ã¼ãã§ã¯æ®å¿µãªããæè¯åªå
æ¢ç´¢ä»¥å¤ã§ã¯ææ°ã®ãããé
ç½®ã解ããªãã£ãã§ã
æè¯åªå
æ¢ç´¢ã¯ç¾å¨ã®ç¤é¢ãè©ä¾¡ãã¦(ã´ã¼ã«ã¾ã§ã®ã³ã¹ããæ¨å®ãã¦)ãè©ä¾¡ããããã®ããé ã«æ¢ç´¢ãã¦ããå¹
åªå
æ¢ç´¢ã®ä¸ç¨®ã§ããä»åã¯ããã«ã®æçµçãªä½ç½®ã¨ã®ãã³ããã¿ã³è·é¢ã®åè¨ã®2.5åã¨ã¹ã¿ã¼ãããã®ç§»ååæ°ã®åãç¤é¢ã®è©ä¾¡ã¨ãã¾ãã
ãã³ããã¿ã³è·é¢ã®åè¨ã®ãã®ãã®ã¨ã¹ã¿ã¼ãããã®ç§»ååæ°ã®åã使ãã¨A*æ¢ç´¢ã«ãªãã¾ããA*æ¢ç´¢ã ã¨å¦çãéã«åããªãã£ãã®ã§ãã³ããã¿ã³è·é¢ã®åè¨ã®2.5åã¨ããé©å½ãªä¿æ°ãããã¦ç¡çç¢ççµãããã¾ãã
é ä½ã¯30ä½ã§ã1ä½ã®å¹³åææ°ã®39.6æã¨ã¯14.8æãå·®ãããã¾ãã
ä»åã¯å¹
åªå
æ¢ç´¢ç³»ã®ã¢ã«ã´ãªãºã ãå®è£
ããã®ã§ã次ã«ãªã«ãããæ©ä¼ãããã°反復深化深さ優先探索ã¨ããå®è£
ãã¦ã¿ããã§ã
åèè³æ
ããããã¨ã°ã°ããªãããã£ãã®ã§åå¼·ã«ãªãã¾ãã
ãã¯ãæãåãããªãã¨è¦ãã¾ããã
1ä½ã®äººã®è¨äº
- A*探索で15パズルにも挑戦してみた。 - 似非学問的な手記
- M.Hiroi's Home Page / Puzzle De Programming
- 15パズル自動解答プログラムの作り方
- GDD2011 DevQuiz のスライドパズル晒し祭りをまとめてみた - Fire and Motion
- 幅優先探索すら知らない素人がDevQuizで満点を取るまでの話
- GDD2011, DevQuizのスライドパズルの解答コードを公開しました - Goto_youthKの徒然日記
- blog.k11i.biz: GDD2011 DevQuiz のスライドパズルに挑戦してみました
ã¹ã©ã¤ãããºã«ã®è§£æ³ç³»ã®è¨äº
æ¢ç´¢ã®ç¨®é¡ã¨ãå¯è¦åã¨ãã®è¨äº
ã½ã¼ã¹ã³ã¼ã
# -*- coding: utf-8 -*- import sys import heapq field = [] for line in sys.stdin: sp = line.split() L = len(sp) field += sp cur = field.index('*') #移åå¯è½ãªå ´æãåæ RIGHT, LEFT, DOWN, UP = [1, -1, L, -L] move = [] for i in xrange(L * L): temp = [] if i % L != L - 1: temp.append(RIGHT) if i % L != 0: temp.append(LEFT) if i / L != L - 1: temp.append(DOWN) if i / L != 0: temp.append(UP) move.append(temp) END = map(str, range(1, L * L)) + ['*'] #ãã³ããã¿ã³è·é¢ãè¨ç® md = 0 for i, n in enumerate(field): n = int(n) if n != '*' else L * L ox = (n - 1) % L oy = (n - 1) / L x = i % L y = i / L md += abs(ox - x) + abs(oy - y) q = [] heapq.heappush(q, (2.5 * md, md, 0, field[::], cur, 0, [])) visited = set([tuple(field)]) for i in xrange(10**8): if not q: break cost_est, md, cost, state, cur, last, history = heapq.heappop(q) for d in move[cur]: #ç´åã®ç¶æ ã«éæ»ãããªã if d == -last: continue temp = state[::] #交æãã temp[cur], temp[cur + d] = temp[cur + d], temp[cur] #ãã³ããã¿ã³è·é¢ã®å·®åãè¨ç® md_diff = 0 for i, n in [(cur, temp[cur]), (cur + d, temp[cur + d])]: n = int(n) if n != '*' else L * L ox = (n - 1) % L oy = (n - 1) / L x = i % L y = i / L md_diff += abs(ox - x) + abs(oy - y) for i, n in [(cur, temp[cur + d]), (cur + d, temp[cur])]: n = int(n) if n != '*' else L * L ox = (n - 1) % L oy = (n - 1) / L x = i % L y = i / L md_diff -= abs(ox - x) + abs(oy - y) #çµäºç¢ºèª key = tuple(temp) if temp == END: print '\n'.join(history + [temp[cur]]) break #訪åæ¸ã¿ãã©ãããç¢ºèª if key in visited or cost + 1 + md + md_diff > 1000: continue else: visited.add(key) heapq.heappush(q, (cost + 1 + 2.5 * (md + md_diff), md + md_diff, cost + 1, temp, cur + d, d, history + [temp[cur]])) else: continue break