python求解八皇后問題

今天突然有個行外的朋友扔了一張圖給我,希望我能幫他用python做一下這個作業(yè)——八皇后問題戒良。



八皇后問題是一種經(jīng)典的數(shù)學(xué)求解問題谋逻,規(guī)則是在8×8的國際象棋棋盤上,要求在每一行(或者每一列)放置一個皇后染苛,且能做到在水平方向鹊漠、豎直方向和斜方向都沒有沖突。

關(guān)于這個問題的編程實現(xiàn),首先我們將棋盤等價于一個8×8的矩陣(二維數(shù)組)躯概,矩陣中的點(x登钥,y)指代棋盤第x行y列的位置。而沖突的自然語言定義是同行楞陷、同列或同對角線怔鳖,那么這個邏輯換算到程序中,我們可以認(rèn)為兩點(x1固蛾,y1)和(x2结执,y2)至少滿足以下四個條件之一:

同行:x1 = x2
同列:y1 = y2
斜線正方向:x1 + y1 = x2 + y2
斜線反方向:x1 - y1 = x2 - y2

一開始看到這個問題的規(guī)則,我有些小瞧了它的難度艾凯,以為通過逐行排除過濾就可以推出可行解献幔,因此稍微整理一下思路就草草開干了,最后毫無疑問地踩了不少坑趾诗。在這個問題上蜡感,逐行定點的方式是可行的,關(guān)鍵在于八皇后問題在這種求解方式下存在死解恃泪,即可能在中途某行進(jìn)行取點時郑兴,發(fā)現(xiàn)該行上沒有一個點符合要求。因此贝乎,八皇后問題的程序求解歸根到底其實是一個回溯遍歷的問題情连。通過回溯,我重新調(diào)整了思路:

1览效、從第一行開始却舀,按照沖突規(guī)則過濾出每行目前可選的位置點集合,取一點锤灿;
2挽拔、如果遇到死解,即當(dāng)前行沒有符合要求的可選點但校,則回退到上一行螃诅,重新取點;
3状囱、直到第八行取到了符合要求的安全位置州刽,求解成功。

捋清了這個編程思路浪箭,利用python實現(xiàn)也就不難了穗椅。

import random
import math

# 棋盤初始化
# params
# -d: 矩陣的大小
def initial_chessboard(d):
  chessboard = [[(x+1, y+1) for y in range(d)] for x in range(d)]
  return chessboard

# 指定行過濾出可選位置并隨機選取一個,作為本行queen的填入位置
# params
# -chessboard:棋盤矩陣
# -rowIndex: 指定矩陣的某一行的序號
# -placePicked:已被選的位置
# -exclusions: 回溯時的排除項列表
def filter_and_pick_place(chessboard, rowIndex, placePicked, exclusions):
  # 取到該行
  row = chessboard[rowIndex]
  # 在后續(xù)過程中保存本行過濾完的可選位置
  alternative = []

  if len(placePicked) != 0:
    # 遍歷本行的每一項
    for column in row:
      # 這個變量標(biāo)志了該位置是否可用奶栖,初始化的時候是False匹表,可用
      available = True
      # 遍歷已被選的位置
      for item in placePicked:
        # 只要有一個出現(xiàn)同列或同對角線门坷,或位于排除項列表中時,將available標(biāo)記為不可用
        if column[1] == item[1] or column[0]+column[1] == item[0]+item[1] or \
          column[0]-column[1] == item[0]-item[1] or column in exclusions:
          available = False
      # 該位置可用袍镀,添加進(jìn)可用項數(shù)組里
      if available:
        alternative.append(column)
  else:
    alternative = row

  if len(alternative) == 0:
    # 死解默蚌,返回0,指示不成功
    return 0
  else:
    # 活解苇羡,隨機挑選位置點绸吸,返回1,指示成功
    randomIndex = math.floor(len(alternative) * random.random())
    pick = alternative[randomIndex]
    placePicked.append(pick)
    return 1

# 根據(jù)最終結(jié)果用圖表展示出來
# params
# -positions: 最終挑選的位置列表
def generate_figure(positions):
  figureSring = ''
  for row in range(8):
    for col in range(8):
      if (row+1, col+1) in positions:
        figureSring += 'x '
      else:
        figureSring += '- '
    figureSring += '\n'
  return figureSring


if __name__ == '__main__':
  chessboard = initial_chessboard(8)
  placePicked = []
  exclusions = [[] for i in range(8)]
  row = 0

  while row < 8:
    success = filter_and_pick_place(chessboard, row, placePicked, exclusions[row])
    if success == 1:
      # 沒有遇到死解设江,繼續(xù)往下
      row += 1
    else:
      # 遇到了死解锦茁,回退到上一行并且將死解的點存入排除項中,重新選點
      row -= 1
      exclusions[row].append(placePicked.pop())
      # 由于是自上而下選點的方式叉存,當(dāng)上一行的點重新選取時码俩,后一行的排除項已經(jīng)沒有意義了,清空
      if row < 7:
        exclusions[row+1] = []
  
  # 打印出棋盤
  print(generate_figure(placePicked))

最終結(jié)果如下:

$ python eight_queens.py
- - - x - - - -
- - - - - - - x
- - - - x - - -
- - x - - - - -
x - - - - - - -
- - - - - - x -
- x - - - - - -
- - - - - x - -
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末歼捏,一起剝皮案震驚了整個濱河市稿存,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瞳秽,老刑警劉巖瓣履,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異练俐,居然都是意外死亡袖迎,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進(jìn)店門痰洒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人浴韭,你說我怎么就攤上這事丘喻。” “怎么了念颈?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵泉粉,是天一觀的道長。 經(jīng)常有香客問我榴芳,道長嗡靡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任窟感,我火速辦了婚禮讨彼,結(jié)果婚禮上护盈,老公的妹妹穿的比我還像新娘豆挽。我一直安慰自己皿渗,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布煎饼。 她就那樣靜靜地躺著,像睡著了一般坡脐。 火紅的嫁衣襯著肌膚如雪司澎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天重荠,我揣著相機與錄音箭阶,去河邊找鬼。 笑死戈鲁,一個胖子當(dāng)著我的面吹牛仇参,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播荞彼,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼冈敛,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了鸣皂?” 一聲冷哼從身側(cè)響起抓谴,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎寞缝,沒想到半個月后癌压,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡荆陆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年滩届,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片被啼。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡帜消,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出浓体,到底是詐尸還是另有隱情泡挺,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布命浴,位于F島的核電站娄猫,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏生闲。R本人自食惡果不足惜媳溺,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望碍讯。 院中可真熱鬧悬蔽,春花似錦、人聲如沸捉兴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至难衰,卻和暖如春钦无,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背盖袭。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工失暂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鳄虱。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓弟塞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拙已。 傳聞我的和親對象是個殘疾皇子决记,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,724評論 2 351

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

  • 【1】 天氣漸漸晴朗起來建车,溫度也快速升高了扩借,我爸的苗子開始賣了。 都說清明前后缤至,種瓜種豆潮罪,春天是一個播種的季節(jié)。 ...
    彭晨龍閱讀 288評論 0 3
  • 調(diào)整呼吸 把你的呼吸降到每分鐘4~6次领斥,將身體調(diào)整到適合自控的生理狀態(tài) 休息 5分鐘給意志力加油出門活動嫉到,哪怕只是...
    巴普倫達(dá)閱讀 159評論 0 0
  • XX: 您好何恶!看到你的招聘,我的心情十分雀躍膊存,情不自禁向你寫這封求職信导而! 求職的原因: 001實現(xiàn)自我價值: 我目...
    傘下素語閱讀 988評論 2 8