若在求解一个问题时,能根据每次所得到的局部最优解,推导出最优或最优目标。那么,我们可以根据这个策略,每次得到局部最优解答,逐步而推导出问题,这种策略称为贪心法。
下面我们看一些简单例题
在N行M列的正整数矩阵中,要求从每行中选出1个数,使得选出的总共N个数的和最大。
[算法分析]
要使总和最大,则每个数要尽可能大,自然应该选每行中最大的那个数。因此,我们设计出如下算法:读入N, M,矩阵数据;Total = 0;
int f(int[][] arr,int m,int n){
//在每一行选取最大的元素
int max;
int sum = 0;
for(int i=0;i<m;i ){
max = arr[i][1];
for(int j=0;j<n;j ){
if(max<arr[i][j])
max = a[i][j];
}
sum = max;
}
return sum;
}
从上例中我们可以看出,和递推法相仿,贪心法也是从问题的某一个初始解出270正在观看 发,向给定的目标递推。但不同的是,推进的每一步不是依据某一固定的递推式,而是做一个局部的最优选择,即贪心选择(在例中,这种贪心选择表现为选择一行中的最大整数),这样,不断的将问题归纳为若干相似的子问题,最终产生出一个全局最优解。
特别注意的是,局部贪心的选择是否可以得出全局最优是能否采用贪心法的关键所在。对于能否使用贪心策略,应从理论上予以证明。下面我们看看另一个问题。
给定一个最大载重量为M的卡车和N种食品,有食盐,白糖,大米等。已知第i种食品的最多拥有Wi公斤,其商品价值为Vi元/公斤,编程确定一个装货方案,使得装入卡车中的所有物品总价值最大。
[算法分析]
因为每一个物品都可以分割成单位块,单位块的利益越大显然总收益越大,所以它局部最优满足全局最优,可以用贪心法解答,方法如下:先将单位块收益按从大到小进行排列,然后用循环从单位块收益最大的取起,直到不能取为止便得到了最优解。
因此我们非常容易设计出如下算法:
... f(...){
//将所有物品按照Vi排序
while(卡车没慢||货物还有){
if(卡车有空间){
就把价值最大的加入;
}
}
}
在解决上述问题的过程中,首先根据题设条件,找到了贪心选择标准(Vi),并依据这个标准直接逐步去求最优解,这种解题策略被称为贪心法。
因此,利用贪心策略解题,需要解决两个问题:
首先,确定问题是否能用贪心策略求解;一般来说,适用于贪心策略求解的问题具有以下特点:
①可通过局部的贪心选择来达到问题的全局最优解。运用贪心策略解题,一般来说需要一步步的进行多次的贪心选择。在经过一次贪心选择之后,原问题将变成一个相似的,但规模更小的问题,而后的每步都是当前看似最佳的选择,且每一个选择都仅做一次。
②原问题的最优解包含子问题的最优解,即问题具有最优子结构的性质。在背包问题中,第一次选择单位重量价值最大的货物,它是第个子问题的最优解,第二次选择剩下的货物中单位重量价值最大的货物,同样是第二个子问题的最优解,依次类推。
③其次,如何选择一一个贪心标准?正确的贪心标准可以得到问题的最优解,在确定采用贪心策略解决问题时,不能随意的判断贪心标准是否正确,尤其不要被表面上看似正确的贪心标准所迷惑。在得出贪心标准之后应给子严格的数学证明。
0-1背包问题:一个旅行者有一个最多能装m公斤的背包,现在有n中物品,每件的重量分别是W1、W2、……、Wn,每件物品的价值分别为C1、C2、……、Cn, 需要将物品放入背包中,要怎么样放才能保证背包中物品的总价值最大?
[算法分析]
由于物品不可分割,无法保证能将背包刚好装满,最后闲置的容量无法将单位重量价值更高的物品放入,此时要是可以将单位重量价值相对低的物品放入,反而会让背包的总价值和单位重量的价值更高。假设现在背包的剩余总重量为5kg,存在一个4kg价值为4.5的物品,一个3kg价值为3的物品,一个2kg价值为2的物品,很显然将3kg和2kg的物品放入背包中所获得的价值更高,虽然没有4kg的物品单位重量的价值高。因此通过贪心算法求解01背包的问题可能得不到问题的最优解,得到的是近似最优解的解。
问题描述
有n个人排队到r个水龙头去打水,他们装满水桶的时间t1、t2…………tn为整数且各不相等,应如何安排他们的打水顺序才能使他们总共花费的时间最少?
输入格式
第一行n,r (n<=500,r<=75)
第二行为n个人打水所用的时间Ti (Ti<=100);输出格式
最少的花费时间
样例输入
3 2
1 2 3
每个人打水用的时间事固定的,所以消耗的总时间最少就要让等待的总时间最少,
等待的时间少其实就是让快的人先打就行了
package 贪心入门;
import java.util.Arrays;
import java.util.Scanner;
public class demo01 {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
int r = cin.nextInt();
int[] arr_spend = new int[n];
int[] arr_wait = new int[r];
for(int i=0;i<n;i ) {
arr_spend[i] = cin.nextInt();
}
Arrays.sort(arr_spend);
int sum = 0;
/*核心代码*/
for(int i = 0;i<n;)
for(int j = 0;j<r && i<n;i ,j ) {
// 统计每组打水的等待时间
arr_wait[j] = arr_spend[i];
// 统计总共打水时间
sum = arr_wait[j];
}
System.out.println(sum);
}
}