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下使用以下代码连接并测试
Apr 09 PHP
PHP mb_convert_encoding 获取字符串编码类型实现代码
Apr 26 PHP
PHP 杂谈《重构-改善既有代码的设计》之三 重新组织数据
Apr 09 PHP
php开发文档 会员收费1期
Aug 14 PHP
php jquery 多文件上传简单实例
Dec 23 PHP
PHP图片裁剪函数(保持图像不变形)
May 04 PHP
基于OpenCart 开发支付宝,财付通,微信支付参数错误问题
Oct 01 PHP
PHP简单实现无限级分类的方法
May 13 PHP
老生常谈php中传统验证与thinkphp框架(必看篇)
Jun 10 PHP
LNMP部署laravel以及xhprof安装使用教程
Sep 14 PHP
因str_replace导致的注入问题总结
Aug 08 PHP
Laravel 使用查询构造器配合原生sql语句查询的例子
Oct 12 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
VFP与其他应用程序的集成
2006/10/09 PHP
PHP5中的时间相差8小时的解决办法
2008/03/28 PHP
PHP下常用正则表达式整理
2010/10/26 PHP
一个简单的php加密解密函数(动态加密)
2013/06/19 PHP
使用PHP下载CSS文件中的所有图片【几行代码即可实现】
2016/12/14 PHP
PHP使用finfo_file()函数检测上传图片类型的实现方法
2017/04/18 PHP
PHP实现json_decode不转义中文的方法
2017/05/20 PHP
原生js实现跨浏览器获取鼠标按键的值
2013/04/08 Javascript
jQuery遍历Form示例代码
2013/09/03 Javascript
下一代Bootstrap的5个特点 超酷炫!
2016/06/17 Javascript
全面介绍javascript实用技巧及单竖杠
2016/07/18 Javascript
js实现弹窗居中的简单实例
2016/10/09 Javascript
Vue下的国际化处理方法
2017/12/18 Javascript
Angular6中使用Swiper的方法示例
2018/07/09 Javascript
trackingjs+websocket+百度人脸识别API实现人脸签到
2018/11/26 Javascript
Electron 如何调用本地模块的方法
2019/02/01 Javascript
[02:03]DOTA2亚洲邀请赛 HGT战队出场宣传片
2015/02/07 DOTA
Python合并字符串的3种方法
2015/05/21 Python
Windows下Python2与Python3两个版本共存的方法详解
2017/02/12 Python
python+selenium实现163邮箱自动登陆的方法
2017/12/31 Python
Win10下python3.5和python2.7环境变量配置教程
2018/09/18 Python
Python操作Excel插入删除行的方法
2018/12/10 Python
python basemap 画出经纬度并标定的实例
2019/07/09 Python
python print 格式化输出,动态指定长度的实现
2020/04/12 Python
python爬虫判断招聘信息是否存在的实例代码
2020/11/20 Python
HTML5触摸事件(touchstart、touchmove和touchend)的实现
2020/05/08 HTML / CSS
中邮全球便购:中国邮政速递物流
2017/03/04 全球购物
个人职业生涯规划书1500字
2013/12/31 职场文书
低碳环保倡议书
2014/04/14 职场文书
民族团结好少年事迹材料
2014/08/19 职场文书
党的群众路线教育实践活动调研报告
2014/11/03 职场文书
幼儿园母亲节活动总结
2015/02/10 职场文书
农民工工资保障承诺书
2015/05/04 职场文书
Pytorch 统计模型参数量的操作 param.numel()
2021/05/13 Python
Android Gradle 插件自定义Plugin实现注意事项
2022/06/16 Java/Android
Java实现注册登录跳转
2022/06/16 Java/Android