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 heredoc和phpwind的模板技术使用方法小结
Mar 28 PHP
php foreach、while性能比较
Oct 15 PHP
PHP APC缓存配置、使用详解
Mar 06 PHP
php使用百度ping服务代码实例
Jun 19 PHP
PHP批量去除BOM头代码分享
Jun 26 PHP
使用PHP生成图片的缩略图的方法
Aug 18 PHP
深入解析PHP中foreach语句控制数组循环的用法
Nov 30 PHP
smarty循环嵌套用法示例分析
Jul 19 PHP
PHP实现驼峰样式字符串(首字母大写)转换成下划线样式字符串的方法示例
Aug 10 PHP
laravel实现分页样式替换示例代码(增加首、尾页)
Sep 22 PHP
PHP将整数数字转换为罗马数字实例分享
Mar 17 PHP
php实现网页上一页下一页翻页过程详解
Jun 28 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模块 Memcached功能多于Memcache
2011/06/14 PHP
深入PHP5中的魔术方法详解
2013/06/17 PHP
PHP实现图片裁剪、添加水印效果代码
2014/10/01 PHP
php中实现可以返回多个值的函数实例
2015/03/21 PHP
thinkphp微信开之安全模式消息加密解密不成功的解决办法
2015/12/02 PHP
Symfony2之session与cookie用法小结
2016/03/18 PHP
Mac系统下安装PHP Xdebug
2018/03/30 PHP
js创建对象的几种常用方式小结(推荐)
2010/10/24 Javascript
jquery 学习之二 属性(类)
2010/11/25 Javascript
JavaScript高级程序设计(第3版)学习笔记7 js函数(上)
2012/10/11 Javascript
Javascript添加监听与删除监听用法详解
2014/12/19 Javascript
基于JQuery制作可编辑的表格特效
2014/12/23 Javascript
DEDECMS如何为文章添加HOT NEW标志图片
2015/08/14 Javascript
快速学习jQuery插件 Form表单插件使用方法
2015/12/01 Javascript
基于js实现抽红包并分配代码实例
2019/09/19 Javascript
简单了解常用的JavaScript 库
2020/07/16 Javascript
echarts 使用formatter 修改鼠标悬浮事件信息操作
2020/07/20 Javascript
[50:45]2018DOTA2亚洲邀请赛 4.6 淘汰赛 VP vs TNC 第一场
2018/04/10 DOTA
python中使用mysql数据库详细介绍
2015/03/27 Python
python制作爬虫爬取京东商品评论教程
2016/12/16 Python
关于python写入文件自动换行的问题
2018/06/23 Python
kafka-python批量发送数据的实例
2018/12/27 Python
PyCharm中代码字体大小调整方法
2019/07/29 Python
python使用opencv在Windows下调用摄像头实现解析
2019/11/26 Python
python日志通过不同的等级打印不同的颜色(示例代码)
2021/01/13 Python
CSS3动画:5种预载动画效果实例
2017/04/05 HTML / CSS
使用canvas压缩图片上传的方法示例
2020/02/07 HTML / CSS
英国50岁以上人群的交友网站:Ourtime
2018/03/28 全球购物
js实现弹框效果
2021/03/24 Javascript
公司担保书范文
2014/05/21 职场文书
国际贸易求职信
2014/07/05 职场文书
发布会邀请函
2015/01/31 职场文书
Vue + iView实现Excel上传功能的完整代码
2021/06/22 Vue.js
基于MySql验证的vsftpd虚拟用户
2021/11/07 MySQL
VS2019连接MySQL数据库的过程及常见问题总结
2021/11/27 MySQL
java开发双人五子棋游戏
2022/05/06 Java/Android