贪心算法的实际应用
姓名:
班级:
学号:
指导老师:
定义:
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。
也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。
贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题他能产生整体最优解或者是整体最优解的近似解。
贪婪算法(Greedy algorithm)是一种对某些求最优解问题的更简单、更迅速的设计技术。
用贪婪法设计算法的特点是一步一步地进行,常以当前情况为基础根据某个优化测度作最优选择,而不考虑各种可能的整体情况,它省去了为找最优解要穷尽所有可能而必须耗费的大量时间,它采用自顶向下,以迭代的方法做出相继的贪心选择,每做一次贪心选择就将所求问题简化为一个规模更小的子问题,通过每一步贪心选择,可得到问题的一个最优解,虽然每一步上都要保证能获得局部最优解,但由此产生的全局解有时不一定是最优的,所以贪婪法不要回溯。
贪婪算法是一种改进了的分级处理方法。
其核心是根据题意选取一种量度标准。
然后将这多个输入排成这种量度标准所要求的顺序,按这种顺序一次输入一个量。
如果这个输入和当前已构成在这种量度意义下的部分最佳解加在一起不能产生一个可行解,则不把此输入加到这部分解中。
这种能够得到某种量度意义下最优解的分级处理方法称为贪婪算法。
对于一个给定的问题,往往可能有好几种量度标准。
初看起来,这些量度标准似乎都是可取的,但实际上,用其中的大多数量度标准作贪婪处理所得到该量度意义下的最优解并不是问题的最优解,而是次优解。
因此,选择能产生问题最优解的最优量度标准是使用贪婪算法的核心。
一般情况下,要选出最优量度标准并不是一件容易的事,但对某问题能选择出最优量度标准后,用贪婪算法求解则特别有效。
最优解可以通过一系列局部最优的选择即贪心选择来达到,根据当前状态做出在当前看来是最好的选择,即局部最优解选择,然后再去解做出这个选择后产生的相应的子问题。
每做一次贪婪选择就将所求问题简化为一个规模更小的子问题,最终可得到问题的一个整体最优解。
贪心算法可解决的问题通常大部分都有如下的特性:
⑴有一个以最优方式来解决的问题。
为了构造问题的解决方案,有一个候选的对象的集合:比如不同面值的硬币。
⑵随着算法的进行,将积累起其它两个集合:一个包含已经被考虑过并被选出的候选对象,另一个包含已经被考虑过但被丢弃的候选对象。
⑶有一个函数来检查一个候选对象的集合是否提供了问题的解答。
该函数不考虑此时的解决方法是否最优。
⑷还有一个函数检查是否一个候选对象的集合是可行的,也即是否可能往该集合上添加更多的候选对象以获得一个解。
和上一个函数一样,此时不考虑解决方法的最优性。
⑸选择函数可以指出哪一个剩余的候选对象最有希望构成问题的解。
⑹最后,目标函数给出解的值。
为了解决问题,需要寻找一个构成解的候选对象集合,它可以优化目标函数,贪婪算法一步一步的进行。
起初,算法选出的候选对象的集合为空。
接下来的每一步中,根据选择函数,算法从剩余候选对象中选出最有希望构成解的对象。
如果集合中加上该对象后不可行,那么该对象就被丢弃并不再考虑;否则就加到集合里。
每一次都扩充集合,并检查该集合是否构成解。
如果贪婪算法正确工作,那么找到的第一个解通常是最优的。
实例:
[最大整数]设有n个正整数,将它们连接成一排,组成一个最大的多位整数。
例如:n=3时,3个整数13,312,343,连成的最大整数为34331213。
又如:n=4时,4个整数7,13,4,246,连成的最大整数为7424613。
输入:n
N个数
输出:连成的多位数
算法分析:此题很容易想到使用贪心法,按这种标准,很容易找到反例:12,
121应该组成12121而非12112,那么是不是相互包含的时候就从小到大呢?也不一定,如12,123就是12312而非12123,这种情况就有很多种了。
解决方法:其实此题可以用贪心法来求解,只是刚才的标准不对,正确的标准是:先把整数转换成字符串,然后在比较a+b和b+a,如果a+b>=b+a,就把a 排在b的前面,反之则把a排在b的后面。
代码:
String str = "";
ArrayList<String> array = new ArrayList<String>();
Scanner in = new Scanner(System.in);
System.out("Please input the number of data:");
int n = in.nextInt();
System.out("Please input the data:");
while (n-- > 0) {
array.add(in.next());
}
for(int i = 0; i < array.size(); i ++)
for(int j = i + 1; j < array.size(); j ++){
if((array.get(i) + array.get(j)).compareTo(array.get(j) + array.get(i)) < 0){
String temp = array.get(i);
array.set(i, array.get(j));
array.set(j, temp);
}
}
for(int i = 0; i < array.size(); i ++){
str += array.get(i);
}
System.out.println("str=:"+str);
}
小结:
贪心算法所作的选择可以依赖于以往所作过的选择,但决不依赖于将来的选择,也不依赖于子问题的解,因此贪心算法与其他算法相比具有一定的速度优势。
如果一个问题可以同时用几种方法解决,贪心算法应该是最好的选择之一。
个人觉得:贪心算法要比动态规划更难,因为动态规划一般是建立在一些递归之类的算法之上,加上记忆就可以达到效果。
而贪心算法要考虑的东西却更多,特别是怎么证明局部最优就是全局最优。
而一旦证明出来,贪心的代码则比较简单。
参考文献:
《The Art of Computer Programming》Donald E.Knuth著
《Introduction to Algorithms》Thomas H.Cormen,Charles E.Leiserson,Ronald L.Rivest,Clifford Stein著
《算法与数据结构》傅清祥王晓东著。