(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)<s(k)<s(greedy)<s(k+m)<s(greedy+m)恒成立

但是教授如果改选了更远的greedy点的话, 
(1) 要么他仍然可以选择到下一个子问题最优解所选的点, 因为t点落在了[s(greedy), s(k)+m]范围内, 因此他选greedy后, 仍然能继续选择t点, 也同样生成了最优解.

(2) 要么就是greedy点甚至已经比t点还要远了, 因为t点落在了(s(k), s(greedy)), 即满足了s(k)<s(t)<s(greedy)<s(k)+m, 那么此时教授就节省下了一次取水点, 也就是说C(i) = 1+C(greedy) < 1 + 1 + C(t),   (s(t) < s(greedy)), 我们获得了比原先最优解更好新的最优解;

综上, 贪心策略总是生成了最优解;

写出算法.

/*取水问题贪心算法-迭代写法*/
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.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容