算法笔记-贪心算法

贪心算法:保证每一步都是最优,最终结果肯定是最优的(简化了很多问题,不需要你有大局观)

场景:求集合的极限值(最多,最短,最便宜等等等...)

(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 }
View Code

(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);
View Code

   补充:代码第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),性能应该要比上一个好很多。

  

  

猜你喜欢

转载自www.cnblogs.com/wangjianheng/p/11697363.html
今日推荐