算法 - 贪心算法

简介:

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

思想:

把问题分解为多个子问题,只要依次求出子问题的最优解,就能得到最终问题的最优解。即,只需要考虑局部最优,就能得到全局最优。

简单的应用1:剪绳子

问题描述

给你一个长度为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代码实现

迭代法

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));
}

递归法

java 复制代码
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);
}

简单的应用2:背包问题

问题描述

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

解决思路

三种贪心思想:

选择价值最大的物品

选择重量最轻的物品

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

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

Java代码实现

java 复制代码
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;    //返回背包获得的价值
}

简单的应用3:活动选择问题

问题描述

假设有一个需要使某一资源的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是一个可被合法调度、具有最早结束时间的活动。从直觉上来看,这种活动选择方法是一种贪婪技术,他给后面剩下的待调度任务留下了尽可能多的机会。也就是说,此处的贪心选择使得剩下的、未调度的时间最大化。

Java代码实现

java 复制代码
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]);
}
相关推荐
WeiJingYu.2 分钟前
机器学习——随机森林
算法·随机森林·机器学习
丶小鱼丶1 小时前
二叉树算法之【中序遍历】
java·算法
快去睡觉~3 小时前
力扣238:除自身之外数组的乘积
数据结构·算法·leetcode
胖咕噜的稞达鸭5 小时前
单链表专题---暴力算法美学(1)(有视频演示)
算法
秋难降5 小时前
【数据结构与算法】———回溯之美
数据结构·算法
ikkkkkkkl5 小时前
LeetCode:347.前K个高频元素
数据结构·c++·算法·leetcode
筱砚.5 小时前
【数据结构——并查集】
数据结构·算法
F_D_Z6 小时前
【感知机】感知机(perceptron)学习算法的对偶形式
人工智能·学习·算法·支持向量机
发发发发8886 小时前
leetcode 674.最长连续递增序列
java·数据结构·算法·leetcode·动态规划·最长连续递增序列