算法笔记-分支界限法
(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 }