贪心算法——经典习题

来源:互联网 发布:中兴燕郊 知乎 编辑:程序博客网 时间:2024/05/16 09:03
¡贪心算法
§比较直观,容易想到
§对“图”要求高
§很多特殊图上的问题可以贪心,(参见《算法图论》)
§贪心问题的证明比较困难
§有时需要先排序,再贪心

¡  例1 找钱问题,目前的钱币系统1,2,5,10,用来换钱是最优的。

§  贪心的证明

▪      超过10 一定要用10,为什么?

▪      有5在,2的个数一定不超过3,因为如果有3个2,1个5,则换成1个10和1个1。

▪      没5在,2的个数不超过5。1,2凑超过10的,不如把10换掉。

▪      [5..9]一定要用5,为什么?枚举即可。

▪      [2..4]一定要用2,枚举即可。

§  注: {1,5,7}凑10就不可以贪心!

Java代码:
package com.zj;import java.util.Arrays;import java.util.HashMap;import java.util.Map;import java.util.Set;/* * 贪心算法解决超市找零问题( 所用纸币最少) *  * */public class KeepTheChange {public static Map<Integer, Integer> GetChange(int[] money, int sum) {int len = money.length;if (0 == len)return null;Arrays.sort(money);Map map = new HashMap<Integer, Integer>();int[] num = new int[len];for (int i = len - 1; i >= 0; i--) {while (sum >= money[i]) {sum = sum - money[i];num[i]++;}if (sum == 0)break;}for (int i = 0; i < len; i++) {map.put(money[i], num[i]);}return map;}public static void main(String[] arqs) {int[] money = new int[] { 1, 2, 5 };Map map = GetChange(money, 28);Set<Integer> keys = map.keySet();for (Integer i : keys) {System.out.println("value: " + i + "  num: " + map.get(i));}}}

¡  例2 活动安排 有若干个活动第i个开始时间和结束时间是[Si,fi),活动之间不能交叠,求最多安排多少个任务?

§  贪心原则: 按照结束时间排序,找所有不冲突的。

§  简证:有一个其他的最优解,我们把其中的活动也按照结束时间排序,我们可以把其中的任务一个一个换成我们贪心的任务,而不造成冲突。

Java代码:
package com.zj;import java.util.Arrays;import java.util.Collection;import java.util.Collections;import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;/* * 贪心算法:活动安排问题 * */public class ArrangeActivity {public static Activity[] GetActivity(Activity[] activities) {Arrays.sort(activities);int len = activities.length;int count = 0;for (int i = 0; i < len; i++) {for (int j = i + 1; j < len; j++) {if (activities[j] != null && activities[i] != null&& activities[j].start < activities[i].end) {activities[j] = null;count++;}}}Activity[] result = new Activity[len - count];count = 0;for (int i = 0; i < len; i++) {if (activities[i] != null) {result[count] = activities[i];count++;}}return result;}public static void main(String[] arqs) {Activity[] test = new Activity[11];test[0] = new Activity(1, 4);test[1] = new Activity(3, 5);test[2] = new Activity(0, 6);test[3] = new Activity(5, 7);test[4] = new Activity(3, 8);test[5] = new Activity(5, 9);test[6] = new Activity(6, 10);test[7] = new Activity(8, 11);test[8] = new Activity(8, 12);test[9] = new Activity(2, 13);test[10] = new Activity(12, 14);Activity[] result = GetActivity(test);System.out.println("there are " + result.length + "activities");System.out.println("Details:");for (int i = 0; i < result.length; i++) {System.out.println(result[i].start + "  " + result[i].end);}}}/* * 实现Comparable接口 */class Activity implements Comparable<Activity> {int start;int end;public Activity(int x, int y) {this.start = x;this.end = y;}@Overridepublic int compareTo(Activity a1) {if (this.end < a1.end)return -1;if (this.end > a1.end)return 1;return 0;}}

¡  例3 最优装载 一艘船容量有限,想装载尽可能多的集装箱,每个集装箱的体积为xi,如何装载,使得装的集装箱个数尽可能多?

§  分析:贪心策略,按照最小的体积优先

§  简证: 也是通过“换”,把任意一个解所选的集装箱按体积排序,然后按顺序逐个换为我们贪心策略得到的解所选择的集装箱,占用的总体积不会增大……

Java代码:
package com.zj;import java.util.Arrays;/* * 贪心算法:最优装载 * */public class MaxLoad {public static int[] maxLoad(int[] weight, int sum) {int len = weight.length;if (0 == len)return null;Arrays.sort(weight);int count = 0;for (int i = 0; i < len; i++) {if (sum >= weight[i]) {sum = sum - weight[i];count++;}if (sum == 0)break;}int[] result = new int[count];for (int i = 0; i < count; i++)result[i] = weight[i];return result;}public static void main(String[] arqs) {int[] weight = new int[] {1,1,2,3,14};int[] result = maxLoad(weight, 12);System.out.println("total load: "+result.length+" weights");System.out.println("Details:");for(int i=0;i<result.length;i++){System.out.print(result[i]+"  ");}}}

例4 部分背包 一个背包容量有限,若干个物体,每种物品有自己的体积和价值,每个物品可以拿一定比例,请让价值总和最大。

§  分析,按照每种物品“性价比”排。同样可以依靠交换,我们可以把任意解中选择的物品逐个换我们按贪心策略得到的解所选的物品,即换位同样体积的“更贵重”的物品,从而导致解更好。

Java代码:
package com.zj;import java.util.Arrays;/* * 贪心算法:部分背包问题 * */public class PartBag {public static Article[] partbag(Article[] articles, int sum) {int len = articles.length;if (0 == len)return null;Arrays.sort(articles);int count = 0;int last_weight = Integer.MIN_VALUE;for (int i = len - 1; i >= 0; i--) {if (sum >= articles[i].weight) {sum = sum - articles[i].weight;count++;} else if (sum != 0) {last_weight = sum;sum = 0;count++;}}Article[] result = new Article[count];for (int i = 0; i < count; i++) {if (i != count - 1) {result[i] = articles[len - 1 - i];} else {if (last_weight == Integer.MIN_VALUE) {result[i] = articles[len - 1 - i];} else {result[i] = new Article(last_weight,articles[len - 1 - i].value/ articles[len - 1 - i].weight* last_weight);}}}return result;}public static void main(String[] arqs) {Article[] test = new Article[3];test[0] = new Article(2, 10);test[1] = new Article(5, 12);test[2] = new Article(5, 5);Article[] result = partbag(test, 7);System.out.println("there are " + result.length + " articles");System.out.println("Details:");for (int i = 0; i < result.length; i++) {System.out.println("weight:" + result[i].weight + "   value:"+ result[i].value);}}}class Article implements Comparable<Article> {int weight;long value;public Article(int x, long y) {this.weight = x;this.value = y;}@Overridepublic int compareTo(Article a1) {long value_per_weight_1 = this.value;long value_per_weight_2 = a1.value;value_per_weight_1 = value_per_weight_1 / this.weight;value_per_weight_2 = value_per_weight_2 / a1.weight;if (value_per_weight_1 > value_per_weight_2)return 1;if (value_per_weight_1 < value_per_weight_2)return -1;return 0;}}package com.zj;import java.util.Arrays;/* * 贪心算法:部分背包问题 * */public class PartBag {public static Article[] partbag(Article[] articles, int sum) {int len = articles.length;if (0 == len)return null;Arrays.sort(articles);int count = 0;int last_weight = Integer.MIN_VALUE;for (int i = len - 1; i >= 0; i--) {if (sum >= articles[i].weight) {sum = sum - articles[i].weight;count++;} else if (sum != 0) {last_weight = sum;sum = 0;count++;}}Article[] result = new Article[count];for (int i = 0; i < count; i++) {if (i != count - 1) {result[i] = articles[len - 1 - i];} else {if (last_weight == Integer.MIN_VALUE) {result[i] = articles[len - 1 - i];} else {result[i] = new Article(last_weight,articles[len - 1 - i].value/ articles[len - 1 - i].weight* last_weight);}}}return result;}public static void main(String[] arqs) {Article[] test = new Article[3];test[0] = new Article(2, 10);test[1] = new Article(5, 12);test[2] = new Article(5, 5);Article[] result = partbag(test, 7);System.out.println("there are " + result.length + " articles");System.out.println("Details:");for (int i = 0; i < result.length; i++) {System.out.println("weight:" + result[i].weight + "   value:"+ result[i].value);}}}class Article implements Comparable<Article> {int weight;long value;public Article(int x, long y) {this.weight = x;this.value = y;}@Overridepublic int compareTo(Article a1) {long value_per_weight_1 = this.value;long value_per_weight_2 = a1.value;value_per_weight_1 = value_per_weight_1 / this.weight;value_per_weight_2 = value_per_weight_2 / a1.weight;if (value_per_weight_1 > value_per_weight_2)return 1;if (value_per_weight_1 < value_per_weight_2)return -1;return 0;}}

¡  例5 (独木舟) 有n个人,一条独木舟最多可以乘坐两个人且独木舟载重量有限(每条独木舟可载重量相同),每个人体重不一样,求这些人最少需要几条独木舟。

§  分析:最重的人肯定要上船,因此最重的人和另外一个人(船能承受的另外一个尽可能重的人)共乘一条独木舟,问题规模减少2。

Java代码:
package com.zj;import java.util.Arrays;/* * 贪心算法:独木舟问题 * */public class Canoe {public static int maxPerson(int[] weight, int sum) {int len = weight.length;if (0 == len)return 0;Arrays.sort(weight);int count = 0;int index_1 = 0;int index_2 = len - 1;while (index_1 < index_2) {if (weight[index_1] + weight[index_2] <= sum) {index_1++;index_2--;count++;} else {count++;index_2--;}}if (index_1 == index_2)count++;return count;}public static void main(String[] arqs) {int[] weight = new int[] { 5, 84, 85, 80, 84, 83 };System.out.println(maxPerson(weight, 85));}}


0 0
原创粉丝点击