用erlang求解经典数学问题(2)-电梯调度问题

【题目】

    假设电梯只在某一楼层停,然后乘客下电梯步行至各自目的楼层,求电梯应停在哪一层能使乘客步行的楼层数和最少。

【问题分析】

总论:

    采用归纳总结的方法,先分析简单的情况,总结出规律,再推演出算法。

步骤1:分析题目中的输入、输出

    假设楼层有7层,在2至7层下电梯的乘客数量分别为a、b、c、d、e、f,电梯停靠在x层,则所有乘客步行的总层数
        y = |x-2|*a + |x-3|*b + |x-4|*c + |x-5|*d + |x-6|*e + |x-7|*f
    此函数是一个区间段函数,在相邻整数区间段内事一条斜率为正或为负的线段

步骤2:分析区间段

    下面对各个区间段进行分析
    当2=<x<3,y = (x-2)*a - (x-3)*b - (x-4)*c - (x-5)*d - (x-6)*e - (x-7)*f        (1)
                        = (a-(b+c+d+e+f))*x + (3b+4c+5d+6e+7f) - 2a
    当3=<x<4,y = (x-2)*a + (x-3)*b - (x-4)*c - (x-5)*d - (x-6)*e - (x-7)*f        (2)
                        = ((a+b)-(c+d+e+f))*x + (4c+5d+6e+7f) - (2a+3b)
    ......
    当6=<x<7,y = (x-2)*a + (x-3)*b + (x-4)*c + (x-5)*d + (x-6)*e - (x-7)*f      (6)
                        = ((a+b+c+d+e)-f)*x + 7f - (2a+3b+4c+5d+6e)
    由于a、b、c、d、e、f为不小于0的整数,

    如果a > b+c+d+e+f,则函数式(1)~(6)中x的一次项的值都大于0,即斜率为正,在各个整数区间,y都为向上的折线段,因此当x=2时,y为最小值;

    如果a = b+c+d+e+f,则函数式(1)~(6)中x的一次项的值都大于等于0,且前n(1=<n<=6)个算式中x的一次项的值为0,即斜率为0,线段为平行线,后6-n个算式中x的一次项的值大于0,即斜率为正,y为向上的折线段,因此x为集合{x|2=<x<=6, x的一次项的值为0}中的任一值时,y为最小值;

    如果a < b+c+d+e+f,即斜率为负,y为向下的折线段,没有最小值,继续分析a+b与c+d+e+f的大小

步骤3:演绎归纳   

    楼层总楼层为m,在2至m层下电梯的乘客数量分别为n2、n3、n4、…、nm
    当  n2+n3…+np-1               <    np+np+1…nm
         n2+n3…+np-1+np         >  np+1+np+2…nm
    x=p(2<=p<m)时,y为最小值ymin=((n2+…+np) - (np+1+…+nm))*p + np+1*(p+1) + np+2*(p+2) + … + nm*m - n2*2 - n3*3 - … - np*p
    当  n2+n3…+np-1               <    np+np+1…nm
         n2+n3…+np-1+np         =  np+1+np+2…nm
           ……
         n2+n3…+nq-1+nq          =  nq+1…nm
         n2+n3…+nq+nq+1        >  nq+2…nm
    x为集合{x|p=<x<=q, 2=<p=<q<=m, p到q的一次项的值等于0}中的任一值时,y为最小值ymin=((n2+…+np) - (np+1+…+nm))*p + np+1*(p+1) + np+2*(p+2) + … + nm*m - n2*2 - n3*3 - … - np*p
    当  n2                   <  n3+…nm
           ……

         n2+n3…+nm-1   <  nm
    x=m时,y为最小值ymin=((n2+…+np) - (np+1+…+nm))*p + np+1*(p+1) + np+2*(p+2) + … + nm*m - n2*2 - n3*3 - … - np*p

结论:

    函数在各个区间的斜率是单调递增的,如果在两个端点出没有最小值,则函数内必然存在最小值的拐点

【解决方案】

   

 1 -module(elevatorberth).
 2 -export([start/1]).
 3 
 4 %% 入口函数
 5 %% Passengers:形如[{2,3}, {3,5}, {4,2}...]的元祖列表,
 6 %% 元祖的第一个参数表示楼层,第二个参数表示在该楼层下电梯的乘客数量
 7 start(Passengers) ->
 8     [First | Remain] = Passengers,
 9     {Floors, MinSteps} = calu([First], Remain, []),
10     io:format("elevator should berth in ~p~n", [Floors]),
11     io:format("min steps ~p~n", [MinSteps]).
12 
13 %% 计算停靠层的集合和最小的步行总数
14 %% 算法:将全部楼层分为一段段的射线,元祖表示端点的x、y坐标,
15 %%       将各条射线连接成一条折线,求折线的拐点
16 %% CaluedRaysList:计算过的射线端点列表
17 %% CaluedRaysList:待计算的射线端点列表
18 %% Floors:停靠层的集合
19 
20 %% CaluedRaysList为空,全部楼层计算完毕,
21 %% Floors为空,表示折线单调递减
22 calu(CaluedRaysList, [], []) ->
23     [CurrnetRay | _] = CaluedRaysList,
24     {Floor, _} = CurrnetRay,
25     {Floor, min_steps(CaluedRaysList, Floor, 0)};   %停靠在最高楼层
26     
27 %% CaluedRaysList为空,全部楼层计算完毕,
28 %% Floors不为空,表示最后一条射线斜率为0
29 calu(CaluedRaysList, [], Floors) ->    
30     [CurrnetRay | _] = CaluedRaysList,
31     {Floor, _} = CurrnetRay,
32     {Floors ++ [Floor], min_steps(CaluedRaysList, Floor, 0)};
33 calu(CaluedRaysList, RemainRaysList, Floors) ->
34     RaySlope = calu_values_sum(CaluedRaysList, 0) - calu_values_sum(RemainRaysList, 0),
35     [CurrnetRay | _] = CaluedRaysList,
36     {Floor, _} = CurrnetRay,
37     [NextRay | NewRaysList] = RemainRaysList,
38     if
39         RaySlope > 0 ->        %斜率大于0
40             {Floor, min_steps(CaluedRaysList ++ RemainRaysList, Floor, 0)};
41         RaySlope =:= 0 ->    %斜率等于0
42             calu([NextRay] ++ CaluedRaysList, NewRaysList, Floors ++ [Floor]);
43         RaySlope < 0 ->        %斜率小于0    
44             calu([NextRay] ++ CaluedRaysList, NewRaysList, Floors)
45     end.
46             
47 %% 计算元祖列表中值的算术和
48 calu_values_sum([], Sum) ->
49     Sum;
50 calu_values_sum(Passengers, Sum) ->
51     [Current | Remain] = Passengers,
52     {_, Num} = Current,
53     calu_values_sum(Remain, Sum + Num).
54 
55 %% 最小的步行总数    
56 min_steps([], _, Value) ->
57     Value;
58 min_steps(Passengers, Floor, Value) ->
59     [Current | Remain] = Passengers,
60     {CurFloor, CurNum} = Current,
61     min_steps(Remain, Floor, Value + abs(Floor-CurFloor) * CurNum).
运行时结果如下:
16> elevatorberth:start([{2,2},{3,1},{4,1},{5,2},{6,4},{7,10}]).
elevator should berth in [6,7]
min steps 25
ok

 

posted on 2012-12-04 11:47  应无所住而生其心  阅读(1294)  评论(0编辑  收藏  举报

导航