(8)贪心算法-补水问题

案例描述:

  • Gekko教授想横穿NorthDarkota州, 教授在起点带着两公升水, 在喝光水之前能滑行m英里. 他还携带了一份路线图, 上面标明了沿途补水点距离起点的距离. 试求出教授如何以最少取水次数完成旅程的最优方案(给出所真正要取水的点)

输入: m(一次补水后最大续航里程), s[num], L(总路程长度);
输出: B[count]数组, count为路程中取用水的次数, B[i]为第i次取水的点距离起点的路程;

算法设计:
(1) 最优子结构: 从第i个补水点(和起点的距离为s[i])到终点的最优方案是C(i), 那么C(i)是由我这次在最大续航里程范围内(s[i], s[i]+m]所选取的点k, 以及从k点出发的最优方案C(k)组成;
(2) 写出递归式: C(i) = 1 + C(k) , 附带约束条件s(k) <= s(i)+m;
当然了, 也要考虑下边际条件, 那就是临近终点的情况, 此时:
if s(i) + m >= L, 那么C(i) = 1;
(3) 贪心选择: 每次我尽量让教授走得远, 使得最大续航里程被尽量耗完, 减少补水次数;
也就是让C(i) = 1 + C(k)中的取得满足约束条件情况下的最大值;

证明该贪心策略会生成最优解: 
如果教授不选择可续航范围(s(i), s(i)+m]上最远的点的话, 而是通过选择s(k)<=s(greedy)的k点就可以生成最优解, 
那么, 就有从i取水点开始往前走的最优解为C(i) = 1+C(k) = 1+ 1 + C(t), t点落在(s(k), s(k)+m], 且关系s(i)

写出算法.

/*取水问题贪心算法-迭代写法*/
GetWater(m, S[num], L) 
let B[] be a new array, and B[0] = 0;
j = 0;
for i = 0~num-1
    if (S[i] - B[j] > m) 
        j++;
        B[j] = S[i-1];     
    if (L - S[i] <= m)  //尾部的处理;
        B[++j] = S[i];
        return B[];

时间复杂度显然是O(n), 此处n就是输入的S[num]的元素个数num.

你可能感兴趣的:((8)贪心算法-补水问题)