贪心算法:保证每一步都是最优,最终结果肯定是最优的(简化了很多问题,不需要你有大局观)
场景:求集合的极限值(最多,最短,最便宜等等等...)
(1)会议安排
说明:在有限的时间内召开更多的会议,任何两个会议不能有时间冲突。下图是会议详情:
思路:下一个会议要取结束时间最早的(更优的会议持续时间最短,相当于动态的改变开始时间)
代码:
1 <?php 2 $meetings = [ 3 '1' => [3, 6], '2' => [1, 4], '3' => [5, 7], '4' => [2, 5], '5' => [5, 9], 4 '6' => [3, 8], '7' => [8, 11], '8' => [6, 10], '9' => [8, 12], '10' => [12, 14], 5 ]; 6 7 //根据结束时间排序 8 uasort($meetings, function($p1, $p2){ 9 if ($p1[1] == $p2[1]) return 0; 10 return $p1[1] > $p2[1] ? 1 : -1; 11 }); 12 13 //取不冲突 14 $last = null; 15 foreach ($meetings as $k => $meet) { 16 if (($last === null) || ($last !== null && $meet[0] >= $last)) 17 list($res[], $last) = [$k, $meet[1]]; 18 }
(2)最短路径
说明:景区有五个点,求第1个点到其他所有点的最短距离。地图如下:
思路:依次找最近的点。大致过程如下:
当前在1:得知1-2路程为2;1-3路程为5 。下面去2和3(因为1的两个出度分别是2和3)
然后去2:得知2-4路程为6;2-3路程为1; 结合上面新得出的路程:1-3路程为4(1-2-3,要比上面的5小,这里要刷新一下),1-4路程为6(这个分支下面要去3和4)
然后去3:得知 3-4路程为7;3-5路程为1; 结合上面新得出的路程:1-4路程还是4,1-5路程为5(1-2-3-5)(这个分支下面要去4和5)
依次类推...
代码:
1 <?php 2 $map = [ //这里用矩阵表示地图 3 [null, 2, 5, null, null], 4 [null, null, 2, 6, null], 5 [null, null, null, 7, 1], 6 [null, null, 2, null, 4], 7 [null, null, null, null, null], 8 ]; 9 $position = $start = 0; 10 $been = []; //去过的点 11 12 function minPath($position) 13 { 14 global $map, $start, $been; 15 static $res = []; //结果 16 $been[] = $position; //记录走过的点 17 $next = []; 18 foreach ($map[$position] as $k => $v) { 19 if ($v !== null) { 20 if (! isset($res[$start . $k]) || ($res[$start . $k] > $res[$start . $position] + $v)) { 21 $res[$start . $k] = $res[$start . $position] + $v; //记录最短的距离 22 if (in_array($k, $been)) $next[] = $k; //这里放在后面解释 23 } 24 ! in_array($k, $been) && $next[] = $k; //记录接下来要走的点 25 } 26 } 27 28 foreach ($next as $v) { //接着找下个点,这里也是判定递归结束(next为空) 29 minPath($v); 30 } 31 return $res; 32 } 33 $res = minPath($position);
补充:代码第22行注释:
刚开始也没发现这个问题,执行上面的案例也没啥问题。但执行下面这个案例就有问题了(假如没有第22行)。走到第2个点的时候,还判定1-2的距离为8,所以计算1-4为9。等后来走到第3个点,把1-2的距离精确到3,但已经晚了。第2个点已经走过一次,不会再走了。也就是说不会再更新1-4的距离。所以当检测出距离更精确的时候(1-3-2比1-2要近),把那个点(第2个点)从记录走过点的数组中移除,重新在走一次。
或者可以手动遍历一下结果,将需要精确的精确一下,比如当发现1-3-2要比1-2要近,则更新1-2-4(第2个点的所有出度)。但这里要记录路径(只记录1-4=9不行,要记录1-2-4=9),性能应该要比上一个好很多。