关于韩老师在b站Java数据结构中贪心算法忽略的一个小问题
用贪心算法做的一个例题,题目如下:
应用场景-集合覆盖问题
假设存在下面需要付费的广播台,以及广播台信号可以覆盖的地区。 如何选择最少的广播台,让所有的地区都可以接收到信号
广播台:k1,k2,k3,k4,k5
k1覆盖的地区:“北京”,“上海”,“天津”
k2覆盖的地区:“广州”,“北京”,“深圳”
k3覆盖的地区:“成都”,“上海”,“杭州”
k4覆盖的地区:“上海”,“天津”
k5覆盖的地区:“杭州”,“大连”
问题代码和修正代码如下:
代码格式自己复制过来,没有调整。
public class Main { public static void main(String[] args) {
//创建map集合
TreeMap<String, HashSet<String> > mp = new TreeMap<String, HashSet<String>>();
//创建每个广播覆盖的地区
HashSet<String> k1 = new HashSet<String>(); k1.add("北京"); k1.add("上海"); k1.add("天津");
HashSet<String> k2 = new HashSet<String>(); k2.add("北京"); k2.add("广州"); k2.add("深圳");
HashSet<String> k3 = new HashSet<String>(); k3.add("成都"); k3.add("上海"); k3.add("杭州");
HashSet<String> k4 = new HashSet<String>(); k4.add("上海"); k4.add("天津"); HashSet<String> k5 = new HashSet<String>(); k5.add("杭州"); k5.add("大连");
//加入集合
mp.put("k1", k1); mp.put("k2", k2); mp.put("k3", k3); mp.put("k4", k4); mp.put("k5", k5);
//将所有地区放入一个集合
HashSet<String> dQ = new HashSet<String>(); dQ.addAll(k1); dQ.addAll(k2); dQ.addAll(k3); dQ.addAll(k4); dQ.addAll(k5);
//存储结果的集合
LinkedHashSet<String> jG = new LinkedHashSet<String>();
//临时变量,用于存储广播站覆盖地区和未覆盖地区的交集
HashSet<String> jJ = new HashSet<String>();
/创建一个临时变量,用于后面覆盖地区多少来比较
HashSet<String> fG = new HashSet<String>(); //创建一个临时字符串,代表覆盖最多的那个广播站名
String maxGbName = null;
//开始循环选择广播
//如果大于0,就说明还有地区没有覆盖 while(dQ.size() > 0) {
//获取键
for(String key : mp.keySet()) {
//获得该广播覆盖的地区
jJ = mp.get(key);
//求和未覆盖地区的交集 jJ.retainAll(dQ);
//判断顺序,先要打于0,在判断是不是null,如果不是null,在判断和后面的那次交集那个长一点 //因为retainAll方法返回的是boolean类型的,所以不能直接调用size方法// if(jJ.size() > 0 && (maxGbName == null || jJ.size() > ((fG = mp.get(maxGbName)).retainAll(dQ) ).size() ) ) { if(jJ.size() > 0 && maxGbName != null) {// (fG = mp.get(maxGbName) ).retainAll(dQ); fG = mp.get(maxGbName); fG.retainAll(dQ); if(jJ.size() > fG.size() ) { //说明这次覆盖的多些,将该广播名给max maxGbName = key; } } else if(jJ.size() > 0 && maxGbName == null) { //第一次,直接给max maxGbName = key; } } //完以后,将该广播加入 if(maxGbName != null) { jG.add(maxGbName); //删除该广播已经覆盖了的 dQ.removeAll(mp.get(maxGbName) ); //删除mp集合中的广播 mp.remove(maxGbName); }
//清空临时集合和字符串 maxGbName = null; //注意clear的清空,是清空所以,包括谁给它赋值的哪一个,如jJ = k2,那么年k2里面的元素都会被清空,这里应该用null清空 //jJ.clear();//用这个程序会出问题 jJ = null; } //选用的广播 System.out.println(jG); }}