算法笔记-分支界限法

  (1)广度优先

     说明: 

          

 

  代码:

 1 <?php
 2 
 3 $arr = [
 4     'A' => [
 5         'B' => [
 6             'D' => ['H', 'I'],
 7             'E' => ['J'],
 8             'F',
 9         ],
10         'C' => ['G'],
11     ],
12 ];
13 
14 //直接用数组遍历
15 //print_R(bfsArr($arr));
16 
17 
18 //先将数组转成树, 再遍历
19 //$tree = current(buildTree($arr));
20 //$queue = [$tree->val];
21 //print_r(bfsObj([$tree]));
22 
23 
24 function bfsArr($queue) {
25     static $res;
26     $val = key($queue);
27     $out = array_shift($queue);
28     if (is_array($out)) {
29         $res[] = $val;
30         $queue = array_merge($queue, $out);
31     } else {
32         $res[] = $out;
33     }
34     
35     if (!empty($queue)) {
36         bfsArr($queue);
37     }
38     return $res;
39 }
40 
41 function bfsObj($queue) {
42     static $res;
43     $out = array_shift($queue);
44     $res[] = $out->val;
45     $queue = array_merge($queue, $out->nodes);
46     
47     if (!empty($queue)) {
48         bfsObj($queue);
49     }
50     return $res;
51 }
52 
53 
54 function buildTree($arr) {
55     $ret = array();
56     if (is_array($arr)) {
57         foreach ($arr as $k => $v) {
58             if (is_numeric($k)) {
59                 $tree = nodeFactory($v);
60             } else {
61                 $tree = nodeFactory($k);
62                 $tree->nodes = buildTree($v);  
63             }
64             $ret[] = $tree;
65         }
66     } else {
67         return nodeFactory($arr);
68     }
69     return $ret;
70 }
71 
72 
73 function nodeFactory($val) {
74     $node = new stdClass();
75     $node->val = $val;
76     $node->nodes = array();
77     return $node;
78 }

 

  (2)0-1背包

     说明: 

 

   代码:

<?php
$weights = [2, 5, 4, 2];
$values = [6, 3, 5, 4];
$limit = 10;
print_r( bfs());

function bfs($queue = []) {
    static $res;
    global $values;
    
    $node = (array)array_shift($queue);
    $val = celSum($node, $values);
    $res[$val][] = $node;
    $queue = array_merge($queue, childNodes($node));
    
    if (!empty($queue)) {
        bfs($queue);
    }
    ksort($res);
    return end($res);
}

function childNodes($node) {
    global $weights, $values, $limit;
    static $maxVal;
    
    $childNodes = array();
    $nextKey = count($node);
    if (!isset($values[$nextKey])) {
        return array();
    }
    
    //剩余的都装进去的价值
    $fill = array_fill($nextKey, count($weights) - $nextKey, 1);
    $allIn = array_merge($node, $fill);
    $allInVal = celSum($allIn, $values);
    if ($allInVal < $maxVal) {
        return array();
    }
    
    //当前总重量
    $weight = celSum($node, $weights);
    $value = celSum($node, $values);
    
    if ($weight + $weights[$nextKey] <= $limit) {
        $childNodes[] = array_merge($node, [$nextKey => 1]);
        $value += $values[$nextKey];
    }
    $childNodes[] = array_merge($node, [$nextKey => 0]);
    
    //更新最优值
    $maxVal = max($value, $maxVal);
    
    return $childNodes;
}


function celSum($queue, $values) {
    $sum = 0;
    foreach ($queue as $k => $v) {
        $sum += $v * $values[$k];
    }
    return $sum;
}

 

 (3)旅行商问题

     说明: 

    

 

  代码:

 1 <?php
 2 $map = [
 3     [0, 15, 30, 5],
 4     [15, 0, 6, 12],
 5     [30, 6, 0, 3],
 6     [4, 12, 3, 0],
 7 ];
 8 
 9 $p = [1, 2, 3, 4];      //表示4个景点
10 $begin = [1];
11 print_r(bfs([$begin]));
12 
13 function bfs($queue) {
14     static $res;
15     $node = array_shift($queue);
16     $childs = childNodes($node);
17     empty($childs) && $res[celSum($node)][] = $node;
18     $queue = array_merge($queue, $childs);
19     
20     if (!empty($queue)) {
21         bfs($queue);
22     }
23     krsort($res);
24     return end($res);
25 }
26 
27 function childNodes($node) {
28     global $p;
29     $remaind = array_diff($p, $node);
30     $childNodes = array();    
31     foreach ($remaind as $v) {
32         $childNodes[] = array_merge($node, [$v]);
33     }
34     return $childNodes;
35 }
36 
37 function celSum($queue) {
38     $distance = 0;
39     foreach ($queue as $k => $p) {
40         if (isset($queue[$k + 1])) {
41             $distance += distance($queue[$k], $queue[$k + 1]);
42         }
43     }
44     return $distance;
45 }
46 
47 function distance($p1, $p2) {
48     global $map;
49     return $map[$p1 - 1][$p2 - 1];
50 }

 

 (4)最优工程布线

     说明: 

      

 

 

   代码:

 1 <?php
 2 $map = [
 3     [0, 0, 0, 0, 0, -1],
 4     [0, 0, -1, 0, 0, 0],
 5     [0, 0, 0, -1, -1, 0],
 6     [0, -1, 0, 0, 0, 0],
 7     [0, 0, 0, 0, 0, 0],
 8 ];
 9 
10 $a = [1, 0];
11 $b = [3, 5];
12 
13 print_r(bfs([[$a]]));
14 
15 function bfs($queue) {
16     global $b;
17     static $res = array();
18     $path = array_shift($queue);
19     $nextPath = searchPath($path);
20     
21     //找到目标点
22     if (in_array($b, $nextPath)) {
23         array_push($path, $b);
24         array_push($res, $path);
25         $nextPath = [];
26     }
27     
28     foreach ($nextPath as & $v) {
29         $v = array_merge($path, [$v]);
30     }
31     $queue = array_merge($queue, $nextPath);
32     
33     //硬跑太吃内存了, 这里作个优化
34     $queue = array_filter($queue, 'isContinue');
35     $queue && bfs($queue);
36     return $res;
37 }
38 
39 function searchPath($path) {
40     global $map;
41     
42     //上下左右四个点
43     $end = end($path);
44     $nodes = [
45         [$end[0] + 1, $end[1]],
46         [$end[0] - 1, $end[1]],
47         [$end[0], $end[1] + 1],
48         [$end[0], $end[1] - 1],
49     ];
50     return array_filter($nodes, function ($node) use ($path, $map){
51         return isset($map[$node[0]][$node[1]]) && $map[$node[0]][$node[1]] === 0 && !in_array($node, $path);
52     });
53 }
54 
55 function isContinue($path) {
56     //用于记录从出发点开始到其他点的最短距离
57     static $min = array();
58     $end = end($path);
59     $len = count($path);
60     $key = join('_', $end);
61     
62     if (isset($min[$key]) && $len > $min[$key]) {
63         return false;
64     } else {
65         $min[$key] = $len;
66         return true;
67     }
68 }

 

posted @ 2020-03-27 03:23  Dahouzi  阅读(255)  评论(0编辑  收藏  举报