贪心算法基本思想:在对问题求解时,总是做出在当前看来是最好的选择。也就是说不从整体最优上加以考虑,算法得到的是某种意义上的局部最优解。
注意:贪心算法的每一步都是最优的解决方案,但整个算法并不一定是最优的(局部最优解)。
贪心算法的经典应用
部分背包问题
背包问题:在限定条件下,如何从众多物品中选出收益最高的几件物品。
背包问题可细分为以下四种:
- 0-1 背包问题:每件物品都不可再分,要么整个装入背包,要么放弃,不允许出现类似“将物品的 1/3 装入背包”的情况;
- 部分背包问题:每件物品是可再分的,即允许将某件物品的一部分(例如 1/3)放入背包;
- 完全背包问题:挑选物品时,每件物品可以选择多个,也就是说不限物品的数量。
- 多重背包问题:每件物品的数量是有严格规定的,比如物品 A 有 2 件,物品 B 有 3 件。
不同背包问题,对应的解决方案也不用,贪心算法主要解决的就是部分背包问题。
部分背包问题
假设商店中有三种商品,它们各自的重量和收益:
- 商品 1:重量10斤,收益60元;
- 商品 2:重量20斤,收益100元;
- 商品 3:重量30斤,收益120元;
部分背包问题,对于每一件商品,顾客可以只购买其一部分(可再分)。现
现在你有一个最多装50斤商品的背包,你如何购买商品才能使背包中的商品收益达到最大化?
贪心算法思路,计算每个商品的收益率(收益/重量)每次优先选择收益率最大的商品,直到所选商品的总重量达到了50斤。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| internal class Program { private static int N = 3;
private static void Sort(float[] w, float[] p) { float temp; float[] v = new float[N]; for (int i = 0; i < N; i++) { v[i] = p[i] / w[i]; } for (int i = 0; i < N; i++) { for (int j = i + 1; j < N; j++) { if (v[i] < v[j]) { temp = v[i]; v[i] = v[j]; v[j] = temp;
temp = w[i]; w[i] = w[j]; w[j] = temp;
temp = p[i]; p[i] = p[j]; p[j] = temp; } } } }
private static void fractional_knaspack(float[] w, float[] p, float[] result, float W) { float temp = 0; int i = 0; Sort(w, p); while (W > 0) { temp = W > w[i] ? w[i] : W; result[i] = temp / w[i]; W -= temp; i++; } }
private static void Main(string[] args) { float values = 0; float[] w = { 10, 30, 20 }; float[] p = { 60, 100, 120 }; float[] result = { 0, 0, 0 }; float W = 50; fractional_knaspack(w, p, result, W); for (int i = 0; i < w.Length; i++) { if (result[i] == 1) { Console.WriteLine("总重量为{0},总价值为{1}的商品全部装入背包。", w[i], p[i]); values += p[i]; } else if (result[i] == 0) { Console.WriteLine("总重量为{0},总价值为{1}的商品不装入背包。", w[i], p[i]); } else { Console.WriteLine("总重量为{0},总价值为{1}的商品装入{2}%背包。", w[i], p[i], result[i] * 100); values += p[i] * result[i]; } } Console.WriteLine("最终收获的商品价值为{0:N6}。", values); } }
|
输出结果:
总重量为10,总价值为60的商品全部装入背包。
总重量为20,总价值为120的商品全部装入背包。
总重量为30,总价值为100的商品装入66.66667%背包。
最终收获的商品价值为246.666672。