贪心算法其实就是一种分而治之思想的体现。一个大规模的问题,在小规模下达到最优,那么很有可能在整个大规模下也达到最优,但并不绝对。
贪心算法的“贪心”就体现在局部达到最优。
举个可以使用贪心算法的栗子:
/**
* 贪心算法 找硬币
* 有 1 2 5 10 20 50 100 7种纸币面额
*数量3 1 2 1 1 3 5 用最少张找出
*/
public void coinChange() {
//人民币面额
int[] values = {1, 2, 5, 10, 20, 50, 100};
//各种面值的 数量集合
int[] counts = {3, 1, 2, 1, 1, 3, 5};
int need = 442;
for(int i=values.length-1;i>=0;i--){
if(need>=values[i] && counts[i]>0){
System.out.print(values[i]+" ");
need -= values[i];
counts[i]--;
i++;
}
if(need == 0){
break;
}
}
}
使用最少张的纸币,那么局部最优就是每次纸币面额尽量大
在这种情况下使用贪心算法是最优解。
但并一定总是这样,例如下面这个栗子。
/**
* 贪心算法 背包问题
*背包容量M = 150 7个物品 重量 35 30 60 50 40 10 25 价值 10 40 30 50 35 40 30
* 总价值要最大
*/
public static void packageValue(){
int m = 150;
int value = 0;
int[] weight = {35,30,60,50,40,10,25};
int[] values = {10,40,30,50,35,40,30};
Item item1 = new Item(35,10);
Item item2 = new Item(30,40);
Item item3 = new Item(60,30);
Item item4 = new Item(50,50);
Item item5 = new Item(40,35);
Item item6 = new Item(10,40);
Item item7 = new Item(25,30);
List<Item> items = new ArrayList<>();
items.add(item1);
items.add(item2);
items.add(item3);
items.add(item4);
items.add(item5);
items.add(item6);
items.add(item7);
items.sort(null);
for(int i=items.size()-1;i>=0;i--){
Item it = items.get(i);
if(it.getWeight()<m){
m -= it.getWeight();
value += it.getValue();
System.out.println("当前背包容量:"+ m + " 当前总价值:"+ value+" ");
}
}
}
static class Item implements Comparable{
int value;
int weight;
public Item(int weight,int value){
this.weight = weight;
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
@Override
public int compareTo(Object o) {
Item obj =(Item) o;
if(this.value>obj.getValue()){
return 1;
}
else if(this.value<obj.getValue()){
return -1;
}
else{
if(this.weight<obj.weight){
return 1;
}
else{
return -1;
}
}
}
}
这个问题的关键在于什么是局部最优,如果仅像代码中这样找到价值最大,很容易就能发现这并不是最优解。那么局部最优应该是什么?重量最小吗?应该是单位价值最高。
所以在使用贪心算法时,一定要考虑什么才算局部最优?
改进后的程序
/**
* 贪心算法 背包问题
*背包容量M = 150 7个物品 重量 35 30 60 50 40 10 25 价值 10 40 30 50 35 40 30
* 总价值要最大
*/
public static void packageValue(){
int m = 150;
int value = 0;
int[] weight = {35,30,60,50,40,10,25};
int[] values = {10,40,30,50,35,40,30};
Item item1 = new Item(35,10);
Item item2 = new Item(30,40);
Item item3 = new Item(60,30);
Item item4 = new Item(50,50);
Item item5 = new Item(40,35);
Item item6 = new Item(10,40);
Item item7 = new Item(25,30);
List<Item> items = new ArrayList<>();
items.add(item1);
items.add(item2);
items.add(item3);
items.add(item4);
items.add(item5);
items.add(item6);
items.add(item7);
items.sort(null);
for(int i=items.size()-1;i>=0;i--){
Item it = items.get(i);
if(it.getWeight()<=m){
m -= it.getWeight();
value += it.getValue();
System.out.println("当前背包容量:"+ m + " 当前总价值:"+ value+" ");
}
}
}
static class Item implements Comparable{
int value;
int weight;
public Item(int weight,int value){
this.weight = weight;
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
@Override
public int compareTo(Object o) {
Item obj =(Item) o;
if((1.0*this.value/this.weight)>(1.0*obj.getValue()/obj.getWeight())){
return 1;
}
else if((1.0*this.value/this.weight)<(1.0*obj.getValue()/obj.getWeight())){
return -1;
}
else{
return 0;
}
}
}