贪心算法
贪心算法本质就是在对问题求解时,每一步都选最优的结果,这些每步最优结果汇集成问题的最终结果。但这个最终结果不一定是最优结果。因为每一步可能存在多个最优解,贪心算法只会按照顺序选择其中一个。
【例子】存在下表中的站点K1~5,每个站点对应不同的覆盖城市,需要选择最少的站点,覆盖全部城市
站点 | 覆盖城市 |
K1 | 北京,上海,天津 |
K2 | 广州,北京,深圳 |
K3 | 成都,上海,杭州 |
K4 | 上海,天津 |
K5 | 杭州,大连 |
算法分析:
注意上述每步中的最优解有可能不止一个,比如说:allAreas中只剩杭州时,K3和K5交集大小都为1,按照顺序取得的策略,贪心算法会选择K3,而不是K5。如果选择K5花的钱比K3少时,贪心算法获得的结果就不算最优了,但它一定满足都覆盖。根据贪心算法的原理,我们需要一个maxKey指针和Key指针,还需要一个集合allAreas用于存储全部城市。每次循环key指针从K1指到K5,而maxKey指针用于指向循环中,覆盖城市与全部城市交集最大的Kn站点(取得每步的最优解),当5个站点都循环完后,需要把maxKey指向的站点加入到一个专门存储解的集合selects中,同时要删除allAreas中Kn覆盖城市的部分,并重置maxKey。再进行循环,直到allAreas集合大小为0时结束。
代码实现:(注意这里面用了maxKeySize,用于保存交集大小,方便下一次循环产生的交集与之比较,找到最优站点)
package cn.dataStructureAndAlgorithm.demo.tenAlgorithm.greedyAlgorithm;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
public class 贪心算法_greedyAlgorithm_子集覆盖问题 {
public static void main(String[] args) {
//创建各站点
HashMap<String, HashSet<String>> broad= new HashMap<>();
HashSet<String> place1=new HashSet<>();
place1.add("北京");
place1.add("上海");
place1.add("天津");
HashSet<String> place2=new HashSet<>();
place2.add("北京");
place2.add("广州");
place2.add("深圳");
HashSet<String> place3=new HashSet<>();
place3.add("成都");
place3.add("上海");
place3.add("杭州");
HashSet<String> place4=new HashSet<>();
place4.add("上海");
place4.add("天津");
HashSet<String> place5=new HashSet<>();
place5.add("杭州");
place5.add("大连");
broad.put("K1",place1);
broad.put("K2",place2);
broad.put("K3",place3);
broad.put("K4",place4);
broad.put("K5",place5);
//创建需要覆盖的城市集合
HashSet<String> allAreas=new HashSet<>();
allAreas.add("北京");
allAreas.add("上海");
allAreas.add("天津");
allAreas.add("广州");
allAreas.add("深圳");
allAreas.add("成都");
allAreas.add("杭州");
allAreas.add("大连");
//创建一个集合用于存储贪心算法每轮所选择的站点
ArrayList<String> selects=new ArrayList<>();
//创建一个临时集合,用于存储每个站点覆盖的城市
HashSet<String> tempSet=new HashSet<>();
//用于保存循环中的最优站点
String maxKey=null;
//用于保存循环中maxKey对应的站点与allAreas的交集大小
int maxKeySize=0;
while (allAreas.size()>0){//allAreas长度大于0,说明还有城市未必覆盖
for (String key:broad.keySet()) {//应用贪心算法获取最优站点解
tempSet.addAll(broad.get(key));//获取key站点对应的所有城市
tempSet.retainAll(allAreas);//将tempSet的数据与allAreas数据求交集,并赋给tempSet
//tempSet.size()>maxKeySize这句话就是贪心算法的应用
if (tempSet.size()>0 && (maxKey==null || tempSet.size()>maxKeySize)){
maxKey=key;
maxKeySize=tempSet.size();//保存本次的交集大小,方便下一次循环产生的交集与之比较,找到最优站点
}
tempSet.clear();//清空,方便下次循环取值
}
if (maxKey!=null){//说明找到了本次循环的最优站点
selects.add(maxKey);//将找到的最优站点加入到结果集合中
allAreas.removeAll(broad.get(maxKey));//从未覆盖城市集合中删除maxKey对应站点的城市
maxKey=null;//置空
maxKeySize=0;//置零
}
}
System.out.println("贪心算法筛选的解为="+selects);
}
}
贪心算法筛选的解为=[K1, K2, K3, K5]
其他常用算法,见下各链接
【常用十大算法_普里姆(prim)算法,克鲁斯卡尔(Kruskal)算法】
【常用十大算法_迪杰斯特拉(Dijkstra)算法,弗洛伊德(Floyd)算法】
【数据结构与算法整理总结目录 :>】<-- 宝藏在此(doge)