【每日一题】小白初学贪心算法

学习贪心算法所做的第一题,话不多说,题如下:

 “贪心”粗浅理解:每一步都是最优解。


单刀直入,开始分析:

既然是讨论最短时间,那就先把时间分解出来看看有没有突破点
    -->时间 = 过桥时间 + 手电筒传递时间

时间详解:

 “手电传递”:手电只有一个,只要人数大于两人就必定要有传递时间,这个似乎没有什么方式能减缓,用最快的人来回跑。


“过桥时间”,既然明确指出过桥时间是最慢那人的时间,于是慢的人就一定会吃掉这个固定的时间,他的同伴再怎么快也没用,我管他与他同伴的时间差叫做“损耗”,“损耗”产生,那就尽量减小嘛,过桥时间相差不大的两人一起过桥是我想到的一个方法。

策略:
1:将最快的两人送过去;
2:最快的一个把手电筒送回来;
3:最慢的两个过去;
4:第二快的人回来把第一快的人带走。
最慢最快的人如何锁定?简单,排个序,这里我用了升序-->

 数组a[N]是所有人的过河时间,N为总人数。

sum_time是策略需要的总时间。(这个是代码切片,完整代码在下面)

解释:“N-1>2”这里用的是地址下标,下标0和1作为最快的两人早就固定在右边了,作为特殊情况拿出来的是左边到最后只剩下一个人的时候(毕竟每次都是少两人嘛)。

        其实这也不是个完美的法子,毕竟也不可能存在真正完美的方法嘛,
        这个策略其实是用最快的人回跑的时间和通过减少“损耗”赚取的时间相抵消,但如果所有人的过桥时间都很差别不大呢,来回跑的时候是最快的两人单独跑,这又何尝不是又一种“损耗”呢?
(例:1 2 3 3 3 3 3 3 3 3 78 89 99)
这种类似的情况可不罕见。

策略2:(或者叫优化)
有点简陋,其实就让最快的人来回接送其他人

        毕竟“手电传递”的时间无法改变,这个任务由最快的人来完成,那么在无法偷奸耍滑的情况下,似乎也只能用这直接的方式了
就把它当成一个扩展插进去吧(它所解决的问题是策略1在面对“那一堆3”时疲乏的情况)

到此为止了,下面是完整代码:

#include <iostream>
#include <algorithm>
using namespace std;

int main(void)
{
    int N, sum_time = 0; // 总人数与总时长
    cout << "需要过河的人数:";
    cin >> N;

    int *a = new int[N];
    cout << "每个人所需的过河时间:";
    for (int i = 0; i < N; i++)
        cin >> a[i];

    auto f = [](int x, int y)
    {
        return x < y;
    }; // 排序准则

    sort(a, a + N, f); // 升序

    for (sum_time = a[1]; N - 1 > 2; N -= 2)
    { // 先将最快的两人送过去,且每次送完手电筒两人都会在右边待命,所以0号和1号其实是不在左边的
        int time1, time2;

        time1 = a[0] + a[N - 1] + a[1] * 2;
        /*这是策略1
        由于过桥必须要有手电筒,这里的策略是:
        最快的两人先过去->
        最快的人携手电筒回来->最慢的两人过去->第二快的人携手电筒回来并和最快的人回去
        至此完整的送去了最慢两个人
        */

        time2 = a[0] + a[N - 1] + a[0] + a[N - 2];
        /*策略扩展:
        单纯是是由最快的人来回接送慢的人(为配合策略一,所以按两个轮次一算
        */

        sum_time += min(time1, time2);
    }

    if (N - 1 == 2)              // 最快的两人一直在右边,所以0号与1号是不存在的
        sum_time += a[0] + a[2]; // 最快的回来接走最后一人

    cout << "耗时:" << sum_time << endl;

    delete[] a;
}

这个是后日编辑,并不是当时写完就上传了。

小白的第一篇,话有些多,如若不满,还请........................尽情挥洒您的口水。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值