算法入门——贪心算法

    用浅显的话说就是要贪一点,我每次都选择最贪的选择,那么我的最终选择有很大的几率就是最贪(最优)的选择:比如当我中了商城的头奖,有10张店铺免费的优惠券。既然没有分身术,那么只能一家一家去选择,第一次我们肯定要最贪,这个商城最值钱的店铺是哪家我们就去哪家,而后在剩余的店铺去挑选最值钱的第二家店铺,如此循环,当我走完10家的时候,我的所有选择就是最贪的选择,也就是最优选择。这里说一下,贪心的思想可以延伸出冒泡排序--每次我都取出数组的最大值(最小值),当我拿完的时候,数组也就排序好了

                                                                                                                                                                                           ------导读

说明

贪心算法是使所做的选择看起来都是当前最佳的,期望通过所做的局部最优选择来产生一个全局最优解

设计贪心算法的步骤

 1.将优化问题转换成这样一个问题,即先做出选择,再解决剩下的一个子问题

  2.证明原问题总是有一个最优解是贪心选择的得到的,从而说明贪心选择的安全。

  3.说明在做出贪心选择后,剩下的子问题具有这样一个性质。即如果将子问题的最优解和我们所做的贪心选择联合起来,可以得到一个更加负责的动态规划解。

剪绳子问题

 给你一个长度为n的绳子,请把绳子剪成m段(m,n都是整数,且都大于1)每段绳子的长度即为K[0],K[1],K[2]...K[m]。请问K[0]*k[1]..*k[m]可能的最大乘积是多少

解决思路

 如果我们按照如下的策略剪绳子,则得到的各段绳子的长度的乘积将最大;当n>=5,我们尽可能地剪长度为3的绳子;当剩下的绳子长度为4时,把绳子剪为长度为2的绳子.

  贪心算法的核心是通过局部最优解来得到全局最优解,对于分割问题来说,要使乘积最大,该问题的贪心思想是尽可能去剪为长度为3的绳子!

Java代码

//迭代法
public static int greedy_cut_rope_1(int n)
{
    if(n<2)
        return 0;
    if(n==2)
        return 1;
    if(n==3)
        return 2;
    //尽可能多地去减长度为3的绳子段
    int timesOf3 = n/3;
    //当绳子最后剩下的长度为4的时候,不能再去剪去长度为3的绳子段
    if(n-timesOf3*3==1)
        timesOf3-=1;
    int timesOf2 =(n-timesOf3*3)/2;
    return (int) (Math.pow(3,timesOf3)*Math.pow(2,timesOf2));
}
//递归法
public static int greedy_cut_rope(int n)
{
    if(n==2)
        return 2;
    if(n==3)
        return 3;
    if(n<2)
        return 1;
    //int timesOf3 = n/3;
    if(n==4)
        return 4;
    return 3*greedy_cut_rope(n-3);
}

背包问题

给定N个物品和一个容量为C的背包,物品i的重量为Wi,其价值为Vi,背包问题是如何选择装入背包的物品,使得装入背包中物品的总价值最大。注意在背包问题中,可以将某种物品的一部分装入背包中,但是不可以重复装入。

解决思路

  •   选择价值最大的物品
  •   选择重量最轻的物品
  •   选择单位重量价值最大的物品

毫无疑问,我们当然选择第三种咯。先把性价比最高的全部装入,最后不足全部装入的部分装入。

public static int greedy_knapSack(int[] w,int[] v,int n,int c)
{
    //  假设物品已按单位重量降序排列
    double[] x = new double[10];
    int maxValue =0;
    int i;
    for(i=0;w[i]<c;i++)
    {
        x[i]=1; //将物品 i 装入背包
        maxValue+=v[i];
        c=c-w[i]; // 背包剩余数量
    }
    x[i]=(double)c/w[i];    //物品i装入一部分
    maxValue+=x[i]*v[i];
    return maxValue;    //返回背包获得的价值
}

活动选择问题

假设有一个需要使某一资源的n个活动组成的集合S={a1,a2,a3...an}。该资源一次只能被一个活动占用,每个活动ai有一个开始时间Si和结束时间Fi,且0<=Si<Fi<∞。一旦被选择后,活动ai就占据半开时间区间[Si,Fi)。如果区间[Si,Fi)与 [Sj,Fj)互不重叠,称活动ai与aj是兼容的。活动选择问题就是要选择出一个由互相兼容的问题组成的最大集合

  讨论下面的活动集合S,其中各活动已按结束时间的单调递增顺序进行了排序:

  

解决思路

  对于任意非空子问题Sij,设am是Sij中具有最早结束时间的活动:

    fm=min{fk:ak∈Sij}

  那么:

1.活动am在Sij的某最大兼容活动子集中被使用。

2.子问题Sim为空,所以选择am使子问题Smj为唯一可能非空的子问题

  在解决子问题时,选择am是一个可被合法调度、具有最早结束时间的活动。从直觉上来看,这种活动选择方法是一种贪婪技术,他给后面剩下的待调度任务留下了尽可能多的机会。也就是说,此处的贪心选择使得剩下的、未调度的时间最大化。

//迭代贪心算法
public static void greedy_activity_selector(int[] s,int[] f,boolean[] b)
{
    int n = s.length-1;
    b[1]=true;
    int j=1;
    for(int i =2;i<=n;i++)
    {
        if(s[i]>f[j])
        {
            b[i]=true;
            j=i;
        }else
            b[i]=false;
    }
    for(int i=1;i<b.length;i++)
        System.out.println(b[i]);
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值