一、介紹
-
貪婪算法(貪心算法)是指在對問題進行求解時,在每一步選擇中都採取最好或者最優(即最有利)的選擇,從而希望能夠導致結果是最好或者最優的算法
-
貪婪算法所得到的結果不一定是最優的結果(有時候會是最優解),但是都是相對近似(接近)最優解的結果
二、貪心算法應用-集合覆蓋
1.問題:
假設存在下面需要付費的廣播臺,以及廣播臺信號可以覆蓋的地區。 如何選擇最少的廣播臺,讓所有的地區都可以接收到信號
2.思路分析
- 遍歷所有的廣播電臺, 找到一個覆蓋了最多未覆蓋的地區的電臺(此電臺可能包含一些已覆蓋的地區,但沒有關係)
- 將這個電臺加入到一個集合中(比如ArrayList), 想辦法把該電臺覆蓋的地區在下次比較時去掉。
- 重複第1步直到覆蓋了全部的地區
使用窮舉法
列出每個可能的廣播臺的集合,這被稱爲冪集。假設總的有n個廣播臺,則廣播臺的組合總共有2n -1 個,假設每秒可以計算10個子集
3.代碼實現
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
public class GreedyAlgorithms {
public static void main(String[] args) {
//創建廣播電臺,放入map
Map<String, HashSet<String>> broadcasts = new HashMap<String, HashSet<String>>();
//將各個電臺放入broadcasts
HashSet<String> hashSet1 = new HashSet<>();
hashSet1.add("北京");
hashSet1.add("上海");
hashSet1.add("天津");
HashSet<String> hashSet2 = new HashSet<>();
hashSet2.add("廣州");
hashSet2.add("北京");
hashSet2.add("深圳");
HashSet<String> hashSet3 = new HashSet<>();
hashSet3.add("成都");
hashSet3.add("上海");
hashSet3.add("杭州");
HashSet<String> hashSet4 = new HashSet<>();
hashSet4.add("上海");
hashSet4.add("天津");
HashSet<String> hashSet5 = new HashSet<>();
hashSet5.add("杭州");
hashSet5.add("大連");
broadcasts.put("K1", hashSet1);
broadcasts.put("K2", hashSet2);
broadcasts.put("K3", hashSet3);
broadcasts.put("K4", hashSet4);
broadcasts.put("K5", hashSet5);
ArrayList<String> result = GreedyAlgorithms(broadcasts);
System.out.println(result);
}
public static ArrayList<String> GreedyAlgorithms(Map<String, HashSet<String>> broadcasts) {
//獲取所有城市
ArrayList<String> allAreas = getAllAreas(broadcasts);
//存放選擇的電臺
ArrayList<String> selects = new ArrayList<>();
HashSet<String> tempSet = new HashSet<>();
//定義給maxKey,保存每一次遍歷過程中,能夠覆蓋最大未覆蓋地區對應的電臺的key 例:K1
//如果maxkey不爲空,則會加入到selects
String maxKey;
//如果allAreas不爲0,則表示還沒有覆蓋到所有的地區
while (allAreas.size() != 0) {
//每進行一次while需要將把maxkey置爲空
maxKey = null;
//遍歷broadcasts,取出對應的key
for (String key : broadcasts.keySet()) {
//每進行一次循環情況一次tempSet
tempSet.clear();
//當前這個key能覆蓋的地區
HashSet<String> areas = broadcasts.get(key);
tempSet.addAll(areas);
//求tempSet與allAreas的交集
tempSet.retainAll(allAreas);
//如果當前集合包含的未覆蓋地區的數量比maxKey指向的集合地區還要多
//則把maxkey指向當前集合
//maxKey == null 爲判斷首次進入循環時maxKey爲空。
if (tempSet.size() > 0 && (maxKey == null || tempSet.size() > broadcasts.get(maxKey).size())) {
maxKey = key;
}
}
//循環過後把maxKey加入到selects
selects.add(maxKey);
//把maxkey對應的地區從allAreas中移除
allAreas.removeAll(broadcasts.get(maxKey));
}
return selects;
}
/**
* 獲取到每一個元素,並且去重
*
* @param broadcasts
* @return
*/
public static ArrayList<String> getAllAreas(Map<String, HashSet<String>> broadcasts) {
ArrayList<String> allAreas = new ArrayList<>();
for (Map.Entry entry : broadcasts.entrySet()) {
HashSet<String> temp = (HashSet<String>) entry.getValue();
for (String str : temp) {
if (!allAreas.contains(str)) {
allAreas.add(str);
}
}
}
System.out.println(allAreas);
return allAreas;
}
}
運行效果