版权声明:欢迎大家转载,指正。 https://blog.csdn.net/yin__ren/article/details/83420803
动态规划是先分析子问题,再做选择。而贪心算法则是先做贪心选择,做完选择后,生成了子问题,然后再去求解子问题
- 与动态规划方法相似,是更简单的解决优化问题的方法,通常用于求解优化问题
- 贪婪算法不能保证一定得到最优解
- 对于具有某些特征的问题,贪婪算法有最优解
1. 作业(活动)选择问题
- 对n个作业进行排程,这些作业在执行期间需要专用某个共同的资源
- 选出最多个不冲突的作业
活动集合S( ):
i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | 3 | 0 | 5 | 3 | 5 | 6 | 8 | 8 | 2 | 12 | |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
1. 递归实现
1. 伪代码
//***********活动编号已经按结束时间排序**********
//递归
REC-ACT-SEL (s, f, i, n)
m ← i + 1
while m ≤ n and s[m] < f[i] //find the first activity in S(i) to finish
do m ← m + 1
if m ≤ n
then return {a(m)} and REC-ACT-SEL(s, f, m, n)
else return null
2. 时间复杂度
3. java 代码实现
/**
* 贪心算法的递归解:活动编号已经按结束时间排序
*
* @param s 活动的开始时间
* @param f 活动的结束时间
* @param i 要求解的子问题 S(i)
* @param n 活动集合S的数量
* @param activities 结果记录
* @return 返回 S(i) 的最大兼容活动集
*/
public static ArrayList<Integer> recursiveActivitySelection(int[] s, int[] f, int i, int n, ArrayList<Integer> activities) {
//初始调用时 i = 0
int m = i;
activities.add(m + 1);//保证与活动序号一致(数组从0开始)
while (m < n && s[m] < f[i]) {//查找 S(i) 中最早结束活动
m++;//选择下一个活动
}
if (m < n) {
recursiveActivitySelection(s, f, m, n, activities);
}
return activities;
}
public static void main(String[] args) {
int[] s = {1, 3, 0, 5, 3, 5, 6, 8, 8, 2, 12};
int[] f = {4, 5, 6, 7, 9, 9, 10, 11, 12, 14, 16};
ArrayList arr = JobSchedule.recursiveActivitySelection(s, f, 0, s.length, new ArrayList<>());
for (int i = 0; i < arr.size(); i++) {
System.out.println(arr.get(i));
}
}
2. 迭代实现
1. 伪代码
//***********活动编号已经按结束时间排序**********
//迭代
GREEDY-ACTIVITY-SELECTOR(s, f)
n = s.length
A ← {a1}
k ← 1
for m ← 2 to n
do if s[m] ≥ f[k] //activity a(m) is compatible with a(k)
then A ← A and {a(m)}
k ← m // a(i) is most recent addition to A
return A
2. 时间复杂度
3. Java 代码实现
/**
* 贪心算法的迭代解:活动编号已经按结束时间排序
*
* @param s 活动的开始时间
* @param f 活动的结束时间
* @param activities 结果记录
* @return 返回 S(i) 的最大兼容活动集
*/
public static ArrayList<Integer> greedyActivitySelection(int[] s, int[] f, ArrayList<Integer> activities) {
//所有真正的活动(不包括 活动0和 活动n+1)中,结束时间最早的那个活动一定是最大兼容活动集合中的 活动.
int n = s.length;
int m = 0;//从 1 开始(数组序号为0)
activities.add(m + 1);//保证与活动序号一致(数组从0开始)
for (int actId = 1; actId < n; actId++) {
if (s[actId] >= f[m])//actId的开始时间在 m 号活动之后.--actId 与 m 没有冲突
{
m = actId;
activities.add(m + 1);
}
}
return activities;
}
public static void main(String[] args) {
int[] s = {1, 3, 0, 5, 3, 5, 6, 8, 8, 2, 12};
int[] f = {4, 5, 6, 7, 9, 9, 10, 11, 12, 14, 16};
ArrayList arr = JobSchedule.greedyActivitySelection(s, f, new ArrayList<>());
for (int i = 0; i < arr.size(); i++) {
System.out.println(arr.get(i));
}
}
}
3. 动态规划实现
//笔者为看懂,望大神指教
2. Huffman 编码
编码文件需要的二进制位:
c.freq
表示 c 在文件中出现的频率- 表示 c 的叶节点在树中的深度
- 定义为 T 的代价
1. 伪代码
HUFFMAN(C)
n = |C|
Q = C
for i = 1 to n – 1
do allocate a new node z
z.left = x = EXTRACT-MIN(Q)
z.right = y = EXTRACT-MIN(Q)
z.freq = x.freq + y.freq
INSERT (Q, z)
return EXTRACT-MIN(Q)
2. 时间复杂度
3. Java 代码实现
public class Huffman {
//定义TreeNode节点
private static class TreeNode implements Comparable<TreeNode> {
TreeNode left;
TreeNode right;
int weight;
char ch;//保存相应字符
String code;//code保存0或1
public TreeNode(int weight, TreeNode left, TreeNode right) {
this.weight = weight;
this.left = left;
this.right = right;
this.code = "";
}
@Override
public int compareTo(TreeNode o) {
if (this.weight > o.weight) {
return 1;
} else if (this.weight < o.weight) {
return -1;
} else {
return 0;
}
}
}
public static TreeNode huffman(TreeMap<Integer, Character> data) {
TreeSet<TreeNode> tNodes = new TreeSet<>();
Set<Integer> weights = data.keySet();
Iterator<Integer> iterator = weights.iterator();
while (iterator.hasNext()) {
int weight = iterator.next();
TreeNode tmp = new TreeNode(weight, null, null);
tmp.ch = data.get(weight);
tNodes.add(tmp);
}
while (tNodes.size() > 1) {
TreeNode leftNode = tNodes.pollFirst();
leftNode.code = "0";
TreeNode rightNode = tNodes.pollFirst();
rightNode.code = "1";
TreeNode newNode = new TreeNode(leftNode.weight + rightNode.weight, leftNode, rightNode);
tNodes.add(newNode);
}
return tNodes.first();
}
//得到字符编码
private static void code(TreeNode t) {
if (t.left != null) {
t.left.code = t.code + t.left.code;
code(t.left);
}
if (t.right != null) {
t.right.code = t.code + t.right.code;
code(t.right);
}
}
//打印字符编码结果
public static void print(TreeNode root) {
if (root != null) {
if (root.left == null && root.right == null) {
System.out.println(root.ch + " 编码:" + root.code);
} else {
print(root.left);
print(root.right);
}
}
}
public static void main(String[] args) {
TreeMap<Integer, Character> test = new TreeMap<>();
test.put(5, 'f');
test.put(9, 'e');
test.put(12, 'c');
test.put(13, 'b');
test.put(16, 'd');
test.put(45, 'a');
TreeNode root = huffman(test);
code(root);
print(root);
}
}
3. 0/1背包问题
- 0-1背包问题 推荐阅读
问题描述:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高
- 如果你作出贪婪选择,即装入平均价值最高的物件,你最终不可能获得最大化的价值总量