贪心算法解决电台问题:
贪心算法:局部最优退出全局最优,找不出明显的反例来否决这个假设
主要思路:
- 1、遍历所有电台k1~Kn 找到一个能覆盖最多 还没覆盖地区 的电台
- 2、将这个电台加入到一个集合中(如ArrayList,最后需要的电台结果就是放在这里面的),将该电台覆盖的地区在下次比较的时候去掉
- 3、重复上述直到覆盖全部地区
主要使用HashSet:
- 1、是因为Set集合元素不可重复,
- 2、方法:tempSet.retainAll(allAreas);求交集并赋值给tempSet
- 3、方法:tempSet.addAll(areas);直接把一个hashSet的全部元素添加到另外一个hasSet中
- 4、方法: set1.removeAll(set2) 这个方法去研究一下,根据debug,删除的是两者(set1,set2)的交集
代码实现思路:
- 1、创建hashMap存放广播电台,key就是电台名称,value就是电台能覆盖的地区(地区是个set集合)
- 2、创建一个set :
HashSet<String> allAreas
存放所有需要覆盖电台的地区(后来要对这些地区进行贪心算法分配) - 3、创建
ArrayList<String> selects
放选择电台(最终结果) - 4、创建
HashSet<String> tempSet
用于存放遍历过程中 电台覆盖的地区 和 当前还没有覆盖的地区的交集,它的size就可以用来判断下次遍历选哪个电台 - 5、定义String maxKey , 保存在一次遍历过程中,能够覆盖最大未覆盖的地区对应的电台的key(tempSet最大值对应的key)
- 6、如果上面的maxKey != null,说明找到了目标电台,就可以放入到集合selects中去
7、主要代码:
while循环操作,只要allAreas 个数!=0,就继续做
7.1 求出maxKey:
7.1.1循环遍历map,获取所有的key,以及key(电台名称)对应的value(覆盖地区)
7.1.2把value放入tempSet中,之后与allArea取交集,并再存入tempSet中
7.1.3如果tempSet包含的未覆盖地区的数量,比maxKey指向的集合还多,重置MaxKey=地区遍历到的key
7.1.4这时候思考到,最外面的while循环,每次进行都要清空maxKey
7.1.5maxKey != null, 就应该将maxKey 加入selects
代码如下:
public class RadioStationGreedyAlgorithm {
public static void main(String[] args) {
greedyAlgorithm();
}
public static void greedyAlgorithm(){
//1、创建hashMap存放广播电台,key就是电台名称,value就是电台能覆盖的地区(地区是个set集合)
HashMap<String, HashSet<String>> broadcasts = new HashMap<>();
//对该hashMap进行初始化
HashSet<String> hashSet1 = new HashSet<>();
hashSet1.add("北京");
hashSet1.add("上海");
hashSet1.add("天津");
HashSet<String> hashSet2 = new HashSet<String>();
hashSet2.add("广州");
hashSet2.add("北京");
hashSet2.add("深圳");
HashSet<String> hashSet3 = new HashSet<String>();
hashSet3.add("成都");
hashSet3.add("上海");
hashSet3.add("杭州");
HashSet<String> hashSet4 = new HashSet<String>();
hashSet4.add("上海");
hashSet4.add("天津");
HashSet<String> hashSet5 = new HashSet<String>();
hashSet5.add("杭州");
hashSet5.add("大连");
broadcasts.put("k1",hashSet1);
broadcasts.put("k2",hashSet2);
broadcasts.put("k3",hashSet3);
broadcasts.put("k4",hashSet4);
broadcasts.put("k5",hashSet5);
//2、创建一个set: HashSet<String> allAreas 存放所有需要覆盖电台的地区(后来要对这些地区进行贪心算法分配)
HashSet<String> allAreas = new HashSet<>();
allAreas.add("北京");
allAreas.add("上海");
allAreas.add("天津");
allAreas.add("广州");
allAreas.add("深圳");
allAreas.add("成都");
allAreas.add("杭州");
allAreas.add("大连");
//3、创建ArrayList<String> selects 放选择电台(最终结果)
ArrayList<String> selects = new ArrayList<>();
//4、创建HashSet<String> tempSet 用于存放遍历过程中 电台覆盖的地区 和 当前还没有覆盖的地区的交集,它的size就可以用来判断下次遍历选哪个电台
HashSet<String> tempSet = new HashSet<>();
//5、定义String maxKey , 保存在一次遍历过程中,能够覆盖最大未覆盖的地区对应的电台的key(tempSet最大值对应的key)
//如果上面的maxKey != null,说明找到了目标电台,就可以放入到集合selects中去
String maxKey = null;
//7、主要代码:while循环操作,只要allAreas 个数!=0,就继续做
while (allAreas.size() != 0){
//每次下面for循环结束后是完成目前 allAreas 的最大maxKey的查找,查找完毕以后应该要删除allArea匹配好的地区,然后接着找
//上面就说明了while循环的意义,那每次肯定都得清空maxKey
maxKey = null;
//求出maxKey
for (Map.Entry<String,HashSet<String>> entry : broadcasts.entrySet()){
String key = entry.getKey(); //每次遍历得到的电台名称k1~kn
HashSet<String> value = entry.getValue(); //电台覆盖的地区
//!!注意!一定记得清空tempSet
tempSet.clear();
tempSet.addAll(value);//把value的地区先全部给tempSet
tempSet.retainAll(allAreas);//与allAreas取交集后将交集内容给tempSet,这样方便统计当前电台满足要求的个数
if (tempSet.size() != 0 && (maxKey == null || tempSet.size() > broadcasts.get(maxKey).size())){
maxKey = key; //当前循环遍历到的key
}
}
//每轮for循环结束后,完成一个当前allAreas最佳的电台匹配查找(一次就找到一个maxKey)
//如果找到了这个maxKey,就应该统计到结果 select中去
//这时候应该删除allArea中以及匹配好的地区,然后再进入while循环
if (maxKey != null){
selects.add(maxKey);
//allAreas.removeAll(tempSet);
// ??为什么这样就出错了?因为这里是是for循环,temSet对应的都是最后一个电台的,maxKey是最大的,取debug就知道了
//allAreas.removeAll(broadcasts.get(maxKey));
HashSet<String> set = new HashSet<>();
set = broadcasts.get(maxKey);
allAreas.removeAll(set);
}
}
System.out.println("贪心算法求出的电台搭配:" + selects);
}
}