贪心算法-装载问题

贪心选择算法为算法分析中一种常用算法,通过一系列的选择来得到一个问题的解。它所作的每一个选择都是当前状态下某种意义的最好选择,即贪心选择。希望通过每次所作的贪心选择导致最终结果是问题的一个最优解。这种启发式的策略并不总能奏效,然而在许多情况下确能达到预期的目的。对于可利用贪心算法解决的问题需要同时满足:最优子结构性质和贪心选择性质。

1.贪心选择性质

    所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法的主要区别。在动态规划算法中,每步所作的选择往往依赖于相关子问题的解。因而只有在解出相关子问题后,才能作出选择。而在贪心算法中,仅在当前状态下作出最好选择,即局部最优选择。然后再去解作出这个选择后产生的相应的子问题。贪心算法所作的贪心选择可以依赖于以往所作过的选择,但决不依赖于将来所作的选择,也不依赖于子问题的解。正是由于这种差别,动态规划算法通常以自底向上的方式解各子问题,而贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为一个规模更小的子问题。

对于一个具体问题,要确定它是否具有贪心选择性质,我们必须证明每一步所作的贪心选择最终导致问题的一个整体最优解。通常可以用我们在证明活动安排问题的贪心选择性质时所采用的方法来证明。首先考察问题的一个整体最优解,并证明可修改这个最优解,使其以贪心选择开始。而且作了贪心选择后,原问题简化为一个规模更小的类似子问题。然后,用数学归纳法证明,通过每一步作贪心选择,最终可得到问题的一个整体最优解。其中,证明贪心选择后的问题简化为规模更小的类似子问题的关键在于利用该问题的最优子结构性质。

2.最优子结构性质

    当一个问题的最优解包含着它的子问题的最优解时,称此问题具有最优子结构性质。问题所具有的这个性质是该问题可用动态规划算法或贪心算法求解的一个关键特征。在活动安排问题中,其最优子结构性质表现为:若a是对于正的活动安排问题包含活动1的一个最优解,则相容活动集合a’=a—{1}是对于e’={i∈e:si≥f1}的活动安排问题的一个最优解。

3.贪心算法与动态规划算法的差异

    贪心算法和动态规划算法都要求问题具有最优子结构性质,这是两类算法的一个共同点。但是,对于一个具有最优子结构的问题应该选用贪心算法还是动态规划算法来求解?是不是能用动态规划算法求解的问题也能用贪心算法来求解?下面我们来研究两个经典的组合优化问题,并以此来说明贪心算法与动态规划算法的主要差别。

最优装载问题问题描述:

有一批集装箱要装上一艘载重量为C的轮船,其中集装箱i的重量为Wi。要求在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船。

算法分析:采用重量轻者先装的贪心选择策略,可产生最优装载问题的最优解。

代码实现:

#include <iostream>
using namespace std;

typedef struct Good
{
    int id;
    double weigth;
    bool flag;
}Good;

int main()
{
    int num;
    double container;
    cout<<"The num of Goods:";
    cin>>num;
    cout<<"The container's capacity:";
    cin>>container;
    Good *mygood=new Good[num];
    for(int i=0;i<num;i++)
    {
        mygood[i].flag=false;
        mygood[i].id=i+1;
        cin>>mygood[i].weigth;
    }

    int tempid;
    double tempweight;
    for(int i=0;i<num-1;i++)                           //按货物重量从小到达排序;
        for(int j=0;j<num-i-1;j++)
            if(mygood[j].weigth>mygood[j+1].weigth)
            {
                tempid=mygood[j].id;
                tempweight=mygood[j].weigth;
                mygood[j].id=mygood[j+1].id;
                mygood[j].weigth=mygood[j+1].weigth;
                mygood[j+1].id=tempid;
                mygood[j+1].weigth=tempweight;
            }

    cout<<"After sort:"<<endl;
    for(int i=0;i<num;i++)
    cout<<mygood[i].weigth<<" ";
    cout<<endl;

    for(int i=0;i<num&&mygood[i].weigth<=container;i++)
    {
        mygood[i].flag=true;
        container-=mygood[i].weigth;
    }

    cout<<"Result:"<<endl;
    cout<<"Id"<<"         "<<"Weigth:"<<endl;
    for(int i=0;i<num&&mygood[i].flag==true;i++)
    cout<<mygood[i].id<<"          "<<mygood[i].weigth<<endl;

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

竖子敢尔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值