PHP实现八皇后算法


Posted in PHP onMay 06, 2019

回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。

八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

这边先以4皇后来解释解决步骤:

详细说明

在第一行有四种可能,选择第一个位置放上皇后

PHP实现八皇后算法

第二行原本可以有四种可能摆放,但是第一第二个已经和第一行的皇后冲突了,因此只剩下第三第四个格子了,先选择第三个格子

PHP实现八皇后算法

接下来是第三行,根据规则可以看出,第三行已经没有位置放了,因为都跟第一第二行的皇后冲突,此时返回到第二行第四个

PHP实现八皇后算法

继续来到第三行,发现只有第二个满足条件

PHP实现八皇后算法

然后发现第四行已经不能放了,只能继续返回,返回到第一行,开始下一种可能

PHP实现八皇后算法

按照 1-5 的步骤,可以找到下面的其中一种解法

PHP实现八皇后算法

总而言之,回溯法就是开始一路到底,碰到南墙了就返回走另外一条路,有点像穷举法那样走遍所有的路。

PHP代码实现:

<?php
 
class Backtracking {
 
 protected $chessboard;  // 棋盘 二维数组 表示坐标轴
 protected $N;      // N表示几皇后
 protected $has_set_x;  // 已经设置的x坐标数组 已经设置的x坐标就不能重复了,用于检查坐标是否可用
 protected $has_set_y;  // 已经设置的y坐标数组 已经设置的y坐标就不能重复了,用于检查坐标是否可用
 protected $has_set_site; // 已经设置的点
 
 function __construct($N) {
 // 初始化数据
 $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; // 当前设置第几个皇后
 $start_x = 0;  // 当前的x坐标 从x开始放置尝试
 $permutation_array = array(); // 全部皇后放置成功的排列数组
 while ($current_n < $this->N && $current_n >= 0) {
  $site_result = $this->setQueenSite($current_n, $start_x); // 设置皇后位置
  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) { // 如果是获取所有排列,则设置当前放置失败,让程序回溯继续找到其他排列
   $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坐标从0开始
  $start_x = 0;
  }else {
  // 当前皇后找不到放置的位置,则需要回溯到上一步
  $previous_site = array_pop($this->has_set_site); // 找到上一步皇后的位置
  if(!empty($previous_site)) {
   $start_x = $previous_site['x'] + 1; // 让上一步的皇后的x坐标+1继续尝试放置
   $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--; // 回溯到上一步,即让一个皇后x坐标+1继续尝试放置
  }
 }
 return $permutation_array;
 }
 
 // 设置皇后位置
 public function setQueenSite($n, $start_x) {
 $start_y = $n;
 if($start_x >= $this->N) return false;
 $check_result = $this->checkQueenSite($start_x, $start_y); // 检查当前是否可放置
 if($check_result == true) {
  return array('x' => $start_x, 'y' => $start_y);
 }else { // 不可放置,则x坐标+1,继续尝试
  $start_x++;
  return $this->setQueenSite($n, $start_x);
 }
 }
 
 // 检查皇后位置是否正确
 public function checkQueenSite($x, $y) {
 // 判断当前坐标的横、纵、斜线是否存在已经放置的皇后
 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;
 }
 
 // 删除数组元素
 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种排列

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
用PHP查询搜索引擎排名位置的代码
Jan 05 PHP
smarty中先strip_tags过滤html标签后truncate截取文章运用
Oct 25 PHP
Php图像处理类代码分享
Jan 19 PHP
ThinkPHP之A方法实例讲解
Jun 20 PHP
php禁止浏览器使用缓存页面的方法
Nov 07 PHP
php读取csv文件并输出的方法
Mar 14 PHP
PHP实现过滤掉非汉字字符只保留中文字符
Jun 04 PHP
php实现点击可刷新验证码
Nov 07 PHP
PHP正则表达式过滤html标签属性(DEMO)
May 04 PHP
phpinfo()中Loaded Configuration File(none)的解决方法
Jan 16 PHP
ThinkPHP实现分页功能
Apr 28 PHP
laravel中数据显示方法(默认值和下拉option默认选中)
Oct 11 PHP
Laravel中10个有用的用法小结
May 06 #PHP
Mac下快速搭建PHP开发环境步骤详解
May 05 #PHP
ThinkPHP3.2框架操作Redis的方法分析
May 05 #PHP
tp5框架内使用tp3.2分页的方法分析
May 05 #PHP
小程序微信退款功能实现方法详解【基于thinkPHP】
May 05 #PHP
小程序微信支付功能配置方法示例详解【基于thinkPHP】
May 05 #PHP
php实现的顺序线性表示例
May 04 #PHP
You might like
PHP批量上传图片的具体实现方法介绍.
2014/02/26 PHP
PHP 使用二进制保存用户状态的实例
2018/01/29 PHP
jquery下利用jsonp跨域访问实现方法
2010/07/29 Javascript
无阻塞加载脚本分析[全]
2011/01/20 Javascript
基于jquery的simpleValidate简易验证插件
2014/01/31 Javascript
一个非常全面的javascript URL解析函数和分段URL解析方法
2014/04/12 Javascript
jQuery实现数字加减效果汇总
2014/12/16 Javascript
使用jQuery简单实现模拟浏览器搜索功能
2014/12/21 Javascript
angularJS 中input示例分享
2015/02/09 Javascript
Java遍历集合方法分析(实现原理、算法性能、适用场合)
2016/04/25 Javascript
AngularJS基础 ng-submit 指令简单示例
2016/08/03 Javascript
Bootstrap轮播插件使用代码
2016/10/11 Javascript
12306 刷票脚本及稳固刷票脚本(防挂)
2017/01/04 Javascript
轻松理解Javascript变量的相关问题
2017/01/20 Javascript
JavaScript中Promise的使用详解
2017/02/26 Javascript
angular.fromJson与toJson方法用法示例
2017/05/17 Javascript
Three.js开发实现3D地图的实践过程总结
2017/11/20 Javascript
微信小程序使用wxParse解析html的方法教程
2018/07/06 Javascript
vue-mugen-scroll组件实现pc端滚动刷新
2019/08/16 Javascript
微信小程序实现拖拽功能
2019/09/26 Javascript
vue 解决兄弟组件、跨组件深层次的通信操作
2020/07/27 Javascript
vue界面发送表情的实现代码
2020/09/11 Javascript
初步探究Python程序的执行原理
2015/04/11 Python
Python中的探索性数据分析(功能式)
2017/12/22 Python
python3实现语音转文字(语音识别)和文字转语音(语音合成)
2020/10/14 Python
python代码实现图书管理系统
2020/11/30 Python
在css3中background-clip属性与background-origin属性的用法介绍
2012/11/13 HTML / CSS
探讨HTML5移动开发的几大特性(必看)
2015/12/30 HTML / CSS
日常奢侈品,轻松购物:Verishop
2019/08/20 全球购物
艺术系大学生毕业个人自我评价
2013/09/19 职场文书
《胡杨》教学反思
2014/02/16 职场文书
《冬阳童年骆驼队》教学反思
2014/04/15 职场文书
环保建议书300字
2014/05/14 职场文书
2014年个人技术工作总结
2014/12/08 职场文书
python四个坐标点对图片区域最小外接矩形进行裁剪
2021/06/04 Python
如何利用Python实现一个论文降重工具
2021/07/09 Python