python解決八數(shù)碼問題

八數(shù)碼問題也稱為九宮問題。在3×3的棋盤苗傅,擺有八個(gè)棋子,每個(gè)棋子上標(biāo)有1至8的某一數(shù)字班巩,不同棋子上標(biāo)的數(shù)字不相同渣慕。棋盤上還有一個(gè)空格,與空格相鄰的棋子可以移到空格中抱慌。要求解決的問題是:給出一個(gè)初始狀態(tài)和一個(gè)目標(biāo)狀態(tài)逊桦,找出一種從初始狀態(tài)轉(zhuǎn)變成目標(biāo)狀態(tài)的移動(dòng)棋子步數(shù)最少的移動(dòng)步驟。

一開始也是兩眼一抹黑抑进,連八數(shù)碼是什么都不知道强经,經(jīng)過度娘得到如上結(jié)果。那該如何實(shí)現(xiàn)呢寺渗?如果移動(dòng)數(shù)字的話匿情,8個(gè)數(shù)字兰迫,每次移動(dòng)有4種選擇,那就是32個(gè)種移動(dòng)方案炬称。那移動(dòng)空格就只有4種選擇汁果,一下子清楚了很多。至于存儲(chǔ)方案當(dāng)然是數(shù)組了玲躯,交換起來多方便据德,是吧?
實(shí)現(xiàn)方式呢跷车?最初實(shí)驗(yàn)要求使用回溯算法解決棘利,什么,回溯姓赤?赡译!那不是和深度優(yōu)先一樣嗎仲吏?無腦走找結(jié)果不铆?算了,先試試吧裹唆。

import numpy as np

#返回兩個(gè)數(shù)組對(duì)應(yīng)位置相同值的個(gè)數(shù)
def calc(state1):
    b = np.array([[1, 2, 3], [8, 0, 4], [7, 6, 5]])
    postion = np.where(state1 == b)
    return len(state1[postion])
#打印八數(shù)碼
def showInfo(a):
    for i in range(3):
        for j in range(3):
            print(a[i, j], end='   ')
        print("\n")
    print('->')
directions = ['up', 'down', 'left', 'right']

def SubStates(state):
    subStates = []
    row, col = np.where(state==0)
    for direction in directions:
        if 'left' == direction and col > 0:
            s = state.copy()
            s[row, col],s[row, col - 1] = s[row, col - 1],s[row, col]
            subStates.append(s)
        if 'up'  == direction and row > 0:
            s = state.copy()
            s[row, col],s[row - 1, col] = s[row - 1, col],s[row, col]
            subStates.append(s)
        if 'down'  == direction and row < 2:
            s = state.copy()
            s[row, col],s[row + 1, col] = s[row + 1, col],s[row, col]
            subStates.append(s)
        if 'right'  == direction and col < 2:
            s = state.copy()
            s[row, col],s[row, col + 1] = s[row, col + 1],s[row, col]
            subStates.append(s)
    return subStates
def DFS(first):
    stack = []
    stack.append(first)
    count = -1
    while stack:
        count += 1
        node = stack.pop()
        showInfo(node)
        if calc(node) == 9:
            return True,count
        s = SubStates(node)
        #res = sorted(s, key=calc)
        for x in res:
            stack.append(x)


#主函數(shù)
def main():
    start = np.array([[0, 1, 3], [8, 2, 4], [7, 6, 5]])
    #start = np.array([[2, 8, 3], [1, 0, 4], [7, 6, 5]])
    res,count = DFS(start)
    if res:
        print('經(jīng)過%d次變換結(jié)束' %count)
if __name__ == '__main__':
    main()

用迭代方式很容易的寫出了深度優(yōu)先算法誓斥,可是貌似跑不出結(jié)果。许帐。劳坑。what a fuck,什么鬼成畦?遂找了個(gè)只移動(dòng)兩次的距芬,運(yùn)行,還是不行循帐。隨機(jī)壓棧太瘋狂了框仔,加點(diǎn)約束吧。每次找和最終結(jié)果最相似的出棧應(yīng)該可以拄养。(這里說一下為了防止無限次循環(huán)离斩,用寬度優(yōu)先搜素比較合適,只需把pop()改成pop(0),如果用到排序的話那就要按相似度由高到低排列了)嗯瘪匿,加上這句res = sorted(s, key=calc),壓棧前按相似度由低到高做一次排序跛梗。移動(dòng)兩次的果然跑出來了,可是移動(dòng)多次的還是不行棋弥。
得核偿,再想辦法吧。做一個(gè)界限函數(shù)顽染,用八數(shù)碼迭代出來的層數(shù)加上相似度來搜索漾岳。這個(gè)值在一定限度才入棧聂薪,否則舍棄。
這里我將節(jié)點(diǎn)封裝成一個(gè)類來實(shí)現(xiàn)蝗羊。

import numpy as np

class eightPuzzle(object):

    directions = ['up', 'down', 'left', 'right']
    max = 7
    def __init__(self,arr,cost=0,parent=None):
        self.arr = arr
        self.cost = cost
        self.parent = parent

    def getCost(self):
        return self.cost
    # 返回兩個(gè)數(shù)組對(duì)應(yīng)位置相同值的個(gè)數(shù)
    def calc(self,state):
        final = np.array([[1, 2, 3], [8, 0, 4], [7, 6, 5]])
        postion = np.where(state.arr == final)
        return len(state.arr[postion])

    # 打印八數(shù)碼
    def showInfo(self):
        for i in range(3):
            for j in range(3):
                print(self.arr[i, j], end='   ')
            print("\n")
        print('->')

    def calc2(self, state1, stop):
        for x in stop:
            postion = np.where(state1.arr == x.arr)
            if len(state1.arr[postion]) == 9:
                return True
        return False

    def SubStates(self):
        subStates = []
        row, col = np.where(self.arr==0)
        for direction in self.directions:
            if 'left' == direction and col > 0:
                s = self.arr.copy()
                s[row, col],s[row, col - 1] = s[row, col - 1],s[row, col]
                new = eightPuzzle(s,self.cost+1,self)
                subStates.append(new)
            if 'up'  == direction and row > 0:
                s = self.arr.copy()
                s[row, col],s[row - 1, col] = s[row - 1, col],s[row, col]
                new = eightPuzzle(s, self.cost + 1,self)
                subStates.append(new)
            if 'down'  == direction and row < 2:
                s = self.arr.copy()
                s[row, col],s[row + 1, col] = s[row + 1, col],s[row, col]
                new = eightPuzzle(s, self.cost + 1,self)
                subStates.append(new)
            if 'right'  == direction and col < 2:
                s = self.arr.copy()
                s[row, col],s[row, col + 1] = s[row, col + 1],s[row, col]
                new = eightPuzzle(s, self.cost + 1,self)
                subStates.append(new)
        return subStates
    def DFS(self):
        stack = []
        stop = []
        stack.append(self)
        count = -1
        while True:
            if not stack:
                return False,count,node
            count += 1
            #stack = sorted(stack, key=self.calc)
            node = stack.pop()
            stop.append(node)
            node.showInfo()
            if self.calc(node) == 9:
                return True,count,node
            s = node.SubStates()
            if s:
                res = sorted(s, key=self.calc)
            else:
                continue
            for x in res:
                if (x.cost + 9 - self.calc(x))< eightPuzzle.max:
                    if self.calc2(x,stop):
                        continue
                    stack.append(x)

def showInfo(result):
    for node in result:
        for i in range(3):
            for j in range(3):
                print(node.arr[i, j], end='   ')
            print('\n')
        print('->')
#主函數(shù)
def main():
    #start = np.array([[0, 1, 3], [8, 2, 4], [7, 6, 5]])
    start = np.array([[2, 8, 3], [1, 0, 4], [7, 6, 5]])
    p = eightPuzzle(start)
    res,count,node = p.DFS()
    result = []
    if res:
        print('經(jīng)過%d次變換結(jié)束' %count)
        while node:
            result.append(node)
            node = node.parent
        result.reverse()
        showInfo(result)
    else:
        print('規(guī)定范圍內(nèi)未找到合適路徑藏澳,可增大界值')


if __name__ == '__main__':
    main()

這次經(jīng)過七次搜索得到了最終答案。
這時(shí)候發(fā)現(xiàn)輸出很有意思耀找,會(huì)出現(xiàn)初始狀態(tài)翔悠。因此在深度搜索的過程中加了一個(gè)stop表,用來存儲(chǔ)已經(jīng)出棧的元素野芒,每次入棧的時(shí)候查看若已經(jīng)存在則扔掉蓄愁。此時(shí)運(yùn)行6次出現(xiàn)答案。
結(jié)束狞悲。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末撮抓,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子摇锋,更是在濱河造成了極大的恐慌丹拯,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件荸恕,死亡現(xiàn)場離奇詭異乖酬,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)融求,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門咬像,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人生宛,你說我怎么就攤上這事县昂。” “怎么了陷舅?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵倒彰,是天一觀的道長。 經(jīng)常有香客問我蔑赘,道長狸驳,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任缩赛,我火速辦了婚禮耙箍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘酥馍。我一直安慰自己辩昆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布旨袒。 她就那樣靜靜地躺著汁针,像睡著了一般术辐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上施无,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天辉词,我揣著相機(jī)與錄音,去河邊找鬼猾骡。 笑死瑞躺,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的兴想。 我是一名探鬼主播幢哨,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼嫂便!你這毒婦竟也來了捞镰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤毙替,失蹤者是張志新(化名)和其女友劉穎岸售,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蔚龙,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡冰评,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了木羹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡解孙,死狀恐怖坑填,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情弛姜,我是刑警寧澤脐瑰,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站廷臼,受9級(jí)特大地震影響苍在,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜荠商,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一寂恬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧莱没,春花似錦初肉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽臼隔。三九已至,卻和暖如春妄壶,著一層夾襖步出監(jiān)牢的瞬間摔握,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來泰國打工丁寄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盒发,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓狡逢,卻偏偏與公主長得像宁舰,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子奢浑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,789評(píng)論 25 707
  • 從三月份找實(shí)習(xí)到現(xiàn)在蛮艰,面了一些公司,掛了不少雀彼,但最終還是拿到小米壤蚜、百度、阿里徊哑、京東袜刷、新浪、CVTE莺丑、樂視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,213評(píng)論 11 349
  • 快速小測試:如何重寫下面的語句梢莽?要求不使用條件判斷語句交換兩個(gè)常量的值萧豆。 if (x == a) x= b; el...
    Colay閱讀 834評(píng)論 0 0
  • 如果你感到缺乏什么,就給出你所缺乏的昏名,如果你需要朋友涮雷,就成為別人的朋友。如果你孤獨(dú)轻局,就去讓某人不孤獨(dú)洪鸭。如果你饑餓,...
    白小二閱讀 217評(píng)論 0 0