PHP實(shí)現(xiàn)八皇后算法
回溯算法實(shí)際上一個(gè)類似枚舉的搜索嘗試過程,主要是在搜索嘗試過程中尋找問題的解,當(dāng)發(fā)現(xiàn)已不滿足求解條件時(shí),就“回溯”返回,嘗試別的路徑?;厮莘ㄊ且环N選優(yōu)搜索法,按選優(yōu)條件向前搜索,以達(dá)到目標(biāo)。但當(dāng)探索到某一步時(shí),發(fā)現(xiàn)原先選擇并不優(yōu)或達(dá)不到目標(biāo),就退回一步重新選擇,這種走不通就退回再走的技術(shù)為回溯法,而滿足回溯條件的某個(gè)狀態(tài)的點(diǎn)稱為“回溯點(diǎn)”。
回溯算法的基本思想是:從一條路往前走,能進(jìn)則進(jìn),不能進(jìn)則退回來,換一條路再試。
八皇后問題,是一個(gè)古老而著名的問題,是回溯算法的典型案例。該問題是國際西洋棋棋手馬克斯·貝瑟爾于1848年提出:在8×8格的國際象棋上擺放八個(gè)皇后,使其不能互相攻擊,即任意兩個(gè)皇后都不能處于同一行、同一列或同一斜線上,問有多少種擺法。
這邊先以4皇后來解釋解決步驟:
詳細(xì)說明
在第一行有四種可能,選擇第一個(gè)位置放上皇后
第二行原本可以有四種可能擺放,但是第一第二個(gè)已經(jīng)和第一行的皇后沖突了,因此只剩下第三第四個(gè)格子了,先選擇第三個(gè)格子
接下來是第三行,根據(jù)規(guī)則可以看出,第三行已經(jīng)沒有位置放了,因?yàn)槎几谝坏诙械幕屎鬀_突,此時(shí)返回到第二行第四個(gè)
繼續(xù)來到第三行,發(fā)現(xiàn)只有第二個(gè)滿足條件
然后發(fā)現(xiàn)第四行已經(jīng)不能放了,只能繼續(xù)返回,返回到第一行,開始下一種可能
按照 1-5 的步驟,可以找到下面的其中一種解法
總而言之,回溯法就是開始一路到底,碰到南墻了就返回走另外一條路,有點(diǎn)像窮舉法那樣走遍所有的路。
PHP代碼實(shí)現(xiàn):
<?php class Backtracking { protected $chessboard; // 棋盤 二維數(shù)組 表示坐標(biāo)軸 protected $N; // N表示幾皇后 protected $has_set_x; // 已經(jīng)設(shè)置的x坐標(biāo)數(shù)組 已經(jīng)設(shè)置的x坐標(biāo)就不能重復(fù)了,用于檢查坐標(biāo)是否可用 protected $has_set_y; // 已經(jīng)設(shè)置的y坐標(biāo)數(shù)組 已經(jīng)設(shè)置的y坐標(biāo)就不能重復(fù)了,用于檢查坐標(biāo)是否可用 protected $has_set_site; // 已經(jīng)設(shè)置的點(diǎn) function __construct($N) { // 初始化數(shù)據(jù) $this->N = $N; $this->chessboard = array(); for ($i=0; $i < $N; $i++) { for ($j=0; $j < $N; $j++) { $this->chessboard[$i][$j] = 0; } } $this->has_set_x = array(); $this->has_set_y = array(); $this->has_set_site = array(); } // 獲取排列 public function getPermutation($is_get_on = true) { // is_get_on 是否獲取一種排列 true:是 false:獲取所有排列 $current_n = 0; // 當(dāng)前設(shè)置第幾個(gè)皇后 $start_x = 0; // 當(dāng)前的x坐標(biāo) 從x開始放置嘗試 $permutation_array = array(); // 全部皇后放置成功的排列數(shù)組 while ($current_n < $this->N && $current_n >= 0) { $site_result = $this->setQueenSite($current_n, $start_x); // 設(shè)置皇后位置 if($site_result == true && $current_n + 1 >= $this->N) { // 如果最后的皇后位置放置成功則記錄信息 $permutation_array[] = array_merge($this->has_set_site, array(array('x' => $site_result['x'], 'y' => $site_result['y']))); if($is_get_on == false) { // 如果是獲取所有排列,則設(shè)置當(dāng)前放置失敗,讓程序回溯繼續(xù)找到其他排列 $site_result = false; } } if($site_result == true) { $this->chessboard[$site_result['x']][$site_result['y']] = 1; $this->has_set_x[] = $site_result['x']; $this->has_set_y[] = $site_result['y']; $this->has_set_site[] = array('x' => $site_result['x'], 'y' => $site_result['y']); $current_n++; // 皇后位置放置成功,繼續(xù)設(shè)置下一個(gè)皇后,重置下一個(gè)皇后的x坐標(biāo)從0開始 $start_x = 0; }else { // 當(dāng)前皇后找不到放置的位置,則需要回溯到上一步 $previous_site = array_pop($this->has_set_site); // 找到上一步皇后的位置 if(!empty($previous_site)) { $start_x = $previous_site['x'] + 1; // 讓上一步的皇后的x坐標(biāo)+1繼續(xù)嘗試放置 $this->deleteArrayValue($this->has_set_x, $previous_site['x']); $this->deleteArrayValue($this->has_set_y, $previous_site['y']); $this->chessboard[$previous_site['x']][$previous_site['y']] = 0; } $current_n--; // 回溯到上一步,即讓一個(gè)皇后x坐標(biāo)+1繼續(xù)嘗試放置 } } return $permutation_array; } // 設(shè)置皇后位置 public function setQueenSite($n, $start_x) { $start_y = $n; if($start_x >= $this->N) return false; $check_result = $this->checkQueenSite($start_x, $start_y); // 檢查當(dāng)前是否可放置 if($check_result == true) { return array('x' => $start_x, 'y' => $start_y); }else { // 不可放置,則x坐標(biāo)+1,繼續(xù)嘗試 $start_x++; return $this->setQueenSite($n, $start_x); } } // 檢查皇后位置是否正確 public function checkQueenSite($x, $y) { // 判斷當(dāng)前坐標(biāo)的橫、縱、斜線是否存在已經(jīng)放置的皇后 if(in_array($x, $this->has_set_x)) return false; if(in_array($y, $this->has_set_y)) return false; $operate_array = array( array('operate_x' => '+', 'operate_y' => '+'), array('operate_x' => '-', 'operate_y' => '-'), array('operate_x' => '+', 'operate_y' => '-'), array('operate_x' => '-', 'operate_y' => '+') ); foreach ($operate_array as $key => $value) { $diagonal_x = $x; $diagonal_y = $y; while (true) { eval("\$diagonal_x=$diagonal_x {$value['operate_x']} 1;"); eval("\$diagonal_y=$diagonal_y {$value['operate_y']} 1;"); if($diagonal_x >= $this->N || $diagonal_y >= $this->N || $diagonal_x < 0 || $diagonal_y < 0) break; if($this->chessboard[$diagonal_x][$diagonal_y] == 1) return false; } } return true; } // 刪除數(shù)組元素 public function deleteArrayValue(&$array, $value) { $delete_key = array_search($value, $array); array_splice($array, $delete_key, 1); } } $N = 8; // 8表示獲取8皇后的排列組合 $backtracking = new Backtracking($N); $permutations = $backtracking->getPermutation(false); var_dump($permutations); // 輸出92種排列
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
php 遍歷目錄,生成目錄下每個(gè)文件的md5值并寫入到結(jié)果文件中
本文章向大家介紹php遍歷目錄,生成目錄下每個(gè)文件的md5值并寫入到結(jié)果文件中,需要的朋友可以參考下2016-12-12織夢(mèng)sitemap地圖實(shí)時(shí)推送給百度的教程
這篇文章主要介紹了織夢(mèng)sitemap地圖實(shí)時(shí)推送給百度的教程,需要的朋友可以參考下2015-08-08PHP curl實(shí)現(xiàn)抓取302跳轉(zhuǎn)后頁面的示例
這篇文章主要介紹了PHP curl實(shí)現(xiàn)抓取302跳轉(zhuǎn)后頁面的示例,主要是對(duì)CURLOPT_CUSTOMREQUEST參數(shù)的運(yùn)用,需要的朋友可以參考下2014-07-07session 加入redis的實(shí)現(xiàn)代碼
本篇文章主要介紹了session 加入redis 的實(shí)例,對(duì)session 進(jìn)行了詳細(xì)介紹,并提供了代碼實(shí)例,需要的朋友可以參考下2016-07-07PHP 使用 Imagick 裁切/生成縮略圖/添加水印自動(dòng)檢測(cè)和處理 GIF
這篇文章主要介紹了PHP 使用 Imagick 裁切/生成縮略圖/添加水印自動(dòng)檢測(cè)和處理 GIF的相關(guān)資料,需要的朋友可以參考下2016-02-02yii2框架中使用下拉菜單的自動(dòng)搜索yii-widget-select2實(shí)例分析
這篇文章主要介紹了yii2框架中使用下拉菜單的自動(dòng)搜索yii-widget-select2的方法,介紹了yii-widget-select2的下載,安裝及具體使用技巧,需要的朋友可以參考下2016-01-01Windows下Apache + PHP SESSION丟失的解決過程全紀(jì)錄
這篇文章主要介紹了Windows下Apache + PHP SESSION丟失的解決過程全紀(jì)錄,花費(fèi)了很長(zhǎng)時(shí)間,最終解決的方式卻令人啼笑皆非,郁悶之極。2015-04-04