算法之DFS(深度优先搜索)

10 篇文章 0 订阅

深度优先搜索属于图算法的一种,英文缩写为DFS即Depth First Search.其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次

一、具体步骤

1、从一个支点开始,选择一条分支
2、沿着分支一直走到无路可走
3、重新回到分支,选择另一条路,重复第二步
4、直到所有点全部遍历完成。

二、举例分析

在这里插入图片描述
例:从3出发,有多少路可以选择

  • 3->1->2->5
  • 3->1->2->6
  • 3->1->4
  • 3->7
  • 3->8->9->11
  • 3->8->10->12
1、将图解析为数组模式,相连的用 1 表示,不相连用 0 表示,每个有12元素,放入数组$arr中。
    [1,2,3,4,5,6,7,8,9,10,11,12];
$arr=[
    [0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], //1    与    2、3、4相连
    [1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], //2	与	  1、5、6相连
    [1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0], //3	与	  1、7、8相连
    [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], //4	与	  1相连
    [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], //5	与	  2相连
    [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], //6	与	  2相连
    [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], //7	与	  3相连
    [0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0], //8	与	  3、9、10相连
    [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0], //9	与	  8、11相连
    [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1], //10	与	  8、12相连
    [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0], //11	与	  9相连
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], //12	与	  10相连
];
2、从3开始分别找出与之相连的元素,$arr[2],记录已经走过的元素 $existArr[]=[3]

[1,0,0,0,0,0,1,1,0,0, 0, 0]

//$arr       是初始化数组
//$enter     是起点
//$existArr  是已经走过的元素集合 【3】
//$roadList  是已经走过的路线     3
function findRoad($arr, $enter, $existArr, $roadList)
	 foreach ($arr[2] as $key => $val) {
	 	 //找出相连的元素
	     if ($val == 1) {
	     	  //判断元素是否已经走过
	          if (!in_array($key, $existArr)) {
	          	  //找到相邻的未走过的元素,存入路线
	              $this->walkRoad($arr, $key, $existArr, $roadList);
	          }
	      }
	  }
}
3、相连的元素是1、7、8,并将以找到的元素记录下来 $existArr[]=[3,1,7,8],并从1开始重复第二、第三步。
//$arr       是初始化数组
//$key       是找到相邻的元素     1
//$existArr  是已经走过的元素集合 【3】
//$roadList  是已经走过的路线     3
function walkRoad($arr, $key, $existArr, $roadList){
	//把找到的元素放入已经走过的集合中,防止以后重复走
     $existArr[] = $key;	
     //把找到的元素写入路线中
     $roadList .= '->' . ($key + 1);
     //将路线保存下来
  	 $this->removeRoad($arr[$key],$existArr,$roadList);
     //从找到的元素开始,从新找与之相邻的元素
     $this->findRoad($arr, $key + 1, $existArr, $roadList);
}
4、保存路线的时候,应注意是否是完整的路线。例:【3->1->2】因为下边还有5、6,顾不用保存。
//$original     是走到当前元素$key的状态$arr[$key]    例:走到1,$arr【0】,[0,1,1,1,0,0,0,0,0,0, 0, 0]
//$existArr     是已经走路的元素集合				  【3、1】
//roadList      是走过的路线						  3->1
function  removeRoad($original,$existArr,$roadList){
	//将以走的元素作为key值,value补1    【3=>1,1=>1】
    $testArr=array_combine($existArr,array_fill(0,count($existArr),1));
    //用1可以走的路线状态和已经走的路线状态比较
    $diffArr=array_diff_assoc($original,$testArr);
    //如果为true,则说明没有路可以走了,将路线保存下来
    if(is_bool(array_search(1,$diffArr))){
        $this->roadArr[]=$roadList;
    }
}
三、完整代码
<?php
/**
 * Created by PhpStorm.
 * User: Wallace
 * Date: 2020/5/20
 * Time: 18:00
 */
/*
 * 根据数组去找寻路线
 */
class dfs
{
    private $enter = [];
    public $roadArr = [];

    //初始化路径
    public function getRoad($arr, $enter)
    {
        $this->enter = $enter;
        $existArr = [$this->enter - 1];
        $roadList = $this->enter;

        $this->findRoad($arr, $enter, $existArr, $roadList);
        return $this->roadArr;
    }

    //根据参数,开始寻找路径
    protected function findRoad($arr, $enter, $existArr, $roadList)
    {
        foreach ($arr[$enter - 1] as $key => $val) {
            if ($val == 1) {
                if (!in_array($key, $existArr)) {
                    $this->walkRoad($arr, $key, $existArr, $roadList);
                }
            }
        }
    }

    //限制已经存在的路,写入路线
    protected function walkRoad($arr, $key, $existArr, $roadList)
    {
        $existArr[] = $key;
        $roadList .= '->' . ($key + 1);
        $this->removeRoad($arr[$key],$existArr,$roadList);
        $this->findRoad($arr, $key + 1, $existArr, $roadList);
    }

    //检测是否无路可走
    protected function  removeRoad($original,$existArr,$roadList){
        $testArr=array_combine($existArr,array_fill(0,count($existArr),1));
        $diffArr=array_diff_assoc($original,$testArr);
        if(is_bool(array_search(1,$diffArr))){
            $this->roadArr[]=$roadList;
        }
    }
}

$arr=[
    [0,1,1,1,0,0,0,0,0,0, 0, 0], //1
    [1,0,0,0,1,1,0,0,0,0, 0, 0], //2
    [1,0,0,0,0,0,1,1,0,0, 0, 0], //3
    [1,0,0,0,0,0,0,0,0,0, 0, 0], //4
    [0,1,0,0,0,0,0,0,0,0, 0, 0], //5
    [0,1,0,0,0,0,0,0,0,0, 0, 0], //6
    [0,0,1,0,0,0,0,0,0,0, 0, 0], //7
    [0,0,1,0,0,0,0,0,1,1, 0, 0], //8
    [0,0,0,0,0,0,0,1,0,0, 1, 0], //9
    [0,0,0,0,0,0,0,1,0,0, 0, 1], //10
    [0,0,0,0,0,0,0,0,1,0, 0, 0], //11
    [0,0,0,0,0,0,0,0,0,1, 0, 0], //12
];
$dfs=new dfs();
$roadArr=$dfs->getRoad($arr,3);
var_dump($roadArr);

//结果
array(6) {
  [0]=>
  string(10) "3->1->2->5"
  [1]=>
  string(10) "3->1->2->6"
  [2]=>
  string(7) "3->1->4"
  [3]=>
  string(4) "3->7"
  [4]=>
  string(11) "3->8->9->11"
  [5]=>
  string(12) "3->8->10->12"
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值