爬山法實現 八皇后問題 (Python 實現)

2021-07-02 00:53:59 字數 3348 閱讀 3242

本文主要簡單闡述爬山法的基本演算法思想,並給出用此演算法實現八皇后問題詳細過程

最基本的爬上搜尋演算法表示:(節選自《人工智慧》第二版):

function hill-climbing(problem) return a state thate is a locak maximum

inputs: problem

local variables: current, a node 

neighbor,a node

current = makenode(inital-state(problem));

loop do

neighbor = a highest-valued successor of current ;

if value[neighbor] <= value[current] then return state[current];

current = neighbor ;

演算法特點:

爬山法是乙個向值增加的方向持續移動的簡單迴圈過程--類似於登高,它將會在到達乙個「峰頂」時終止,此時相鄰狀態中沒有比它更高的值。這個演算法不會維護搜尋樹,因此當前節點的資料結構只需要記錄當前狀態和它的目標函式值,它不會前瞻與當前狀態不直接相鄰的那些狀態的值。這裡更高的值是根據具體的應用場景來定的,準確的說是更接近目標狀態的值,由我們設定的啟發式函式來決定哪個值更好,比如我們求解八皇后問題更高的值就是當前格局中皇后衝突對數最少的情況

演算法侷限性:

區域性極大值是乙個比它的每個鄰居狀態都高得到峰頂,但是比全域性最大值(我們要到達的最終狀態)要低,爬山法演算法到達區域性極大值附近就會被拉向峰頂,然後卡在區域性極大值處無處可走。

因此產生了爬山法的變種如隨機爬山法及其變種如隨機爬山法,隨機重新開始的爬山法,模擬退火搜尋能夠非常有效的解決n皇后問題。

求解八皇后問題:

#-*- coding: utf-8 -*- 

import random

#函式一:引數為當前棋盤布局狀態,根據布局判斷當前八皇后布局存在衝突的皇后對數

def get_numof_conflict(status):

num = 0

for i in range(len(status)):

for j in range(i + 1,len(status)):

if status[i] == status[j]:

num += 1

offset = j - i

if abs(status[i]-status[j]) == offset:

num += 1

return num

#函式二:引數為當前棋盤布局狀態,利用爬山法思想選擇鄰居狀態最好的布局並返回

def hill_climbing(status):

convert = {}

length = len(status)

for col in range(length):

best_move = status[col]

for row in range(length):

if status[col] == row:

continue

status_copy = list(status)

status_copy[col] = row

convert[(col,row)] = get_numof_conflict(status_copy)

answers = #最佳後繼集合

conflict_now = get_numof_conflict(status) #當前皇后衝突對數

#遍歷儲存所有可能後繼的字典,找出最佳後繼

for key,value in convert.iteritems():

if value < conflict_now:

conflict_now = value

for key,value in convert.iteritems():

if value == conflict_now:

#如果最佳後繼集合元素大於乙個 隨機選擇乙個

if len(answers) > 0:

x = random.randint(0,len(answers)-1)

col = answers[x][0]

row = answers[x][1]

status[col] = row

return status

#函式三:求得八皇后滿足衝突數為0的乙個解,迴圈輸出每一步的後繼集合 直到不存在衝》突為止

def queens():

status = [0,1,2,3,4,5,6,7] #初始狀態所有皇后都在對角線

#當存在衝突的個數大於0時 迴圈求解最佳後繼 直到找到八皇后解

while get_numof_conflict(status) > 0:

status = hill_climbing(status)

print status

print get_numof_conflict(status)

print "the answer is"

print

print status

if __name__ == '__main__':

queens()

**說明 :

(1)啟發式耗散函式 get_numof_conflict求出可以彼此攻擊2的皇后對的數  hill_climbing是演算法中爬山過程的實現,convert字典中儲存的鍵是所有可能後繼狀態,值是此狀態對應的皇后衝突對數,後面通過遍歷來找到最佳後繼。爬山法演算法通常在最佳後繼集合中隨機選擇乙個進行擴充套件,如果這樣的後繼多於乙個的話

(2)  棋盤的排列用列表 status 表示, 依次表示第一列第二列到第n列的擺放位置。 如列表[0,2,1] 表示3*3矩陣第一列皇后放在最下面一格,第二列放在最上面一格,第三列放在中間一格

(3) 執行結果說明:初始狀態每個皇后都在次對角線上 每次執行程式將輸出求解乙個八皇后正確解的爬山法實現過程 ,依次輸出求解過程每乙個最佳選擇的鄰居狀態和其存在的皇后衝突對數,可以看出在求解過程中 不斷爬山的過程--每進行一步都達到乙個更好的格局,衝突次數更少,最後一行顯示的是八皇后的乙個正確解 衝突數為 0

執行截圖

人工智慧 爬山法解決八皇后問題 python原始碼

八皇后問題,乙個古老而著名的問題,是回溯演算法的典型案例。該問題由國際西洋棋棋手馬克斯 貝瑟爾於 1848 年提出 在 8 8 格的西洋棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行 同一列或同一斜線上,問有多少種擺法。演算法的邏輯流程圖如下所示 源 為 import copy ...

八皇后問題(回溯法)

問題描述 八皇后問題是十九世紀著名數學家高斯於1850年提出的。問題是 在8 8的棋盤上擺放8個皇后,使其不能互相攻擊,即任意的兩個皇后不能處在同意行,同一列,或同意斜線上。可以把八皇后問題拓展為n皇后問題,即在n n的棋盤上擺放n個皇后,使其任意兩個皇后都不能處於同一行 同一列或同一斜線上。問題分...

回溯法 八皇后問題

八皇后問題是高斯於1850年提出的,這是乙個典型的回溯演算法的問題。八皇后問題的大意如下 西洋棋的棋盤有8 行 8 列共64個單元格,在棋盤上擺放八個皇后,使其不能互相攻擊,也就 是說任意兩個皇后都不能處於同一行 同一列或同一斜線上。問總共有多少種擺放方法,每一種擺 放方式是怎樣的。首先來分析八皇后...