java实现贪心算法

算法应用背景

假设存在如下表的需要付费的广播台,以及广播台信号可以覆盖的地区。 如何选择最少的广播台,让所有的地区都可以接收到信号
java实现贪心算法_第1张图片

思路分析

使用贪婪算法, 效率高:
1、目前并没有算法可以快速计算得到准备的值, 使用贪婪算法,则可以得到非常接近的解,并且效率高。选择策略上,因为需要覆盖全部地区的最小集合
2、遍历所有的广播电台,找到一个覆盖了最多未覆盖的地区的电台(此电台可能包含一些已覆盖的地区,但没有关系)
3、将这个电台加入到一个集合中(比如ArrayList),想办法把该电台覆盖的地区,在下次比较时去掉。
4)、重复以上步骤直到覆盖了全部的地区

步骤:

循环所有广播(从k1到k5)一轮
当key=k1时,k1广播能覆盖北京、上海、天津3个地区,maxKey=k1
java实现贪心算法_第2张图片
当key=k2时,k2广播能覆盖广州、深圳、北京3个地区,k2覆盖的地区数量未超过k1,所以maxKey还是等于k1
java实现贪心算法_第3张图片
当key=k3时,k3广播能覆盖上海、深圳、成都3个地区,k3覆盖的地区数量未超过k1,所以maxKey还是等于k1
java实现贪心算法_第4张图片
当key=k4时,k4广播能覆盖上海、天津2个地区,k4覆盖的地区数量未超过k1,所以maxKey还是等于k1
java实现贪心算法_第5张图片

当key=k5时,k5广播能覆盖杭州、大连2个地区,k5覆盖的地区数量未超过k1,所以maxKey还是等于k1
java实现贪心算法_第6张图片

第一轮从k1遍历到k5时,能在“未覆盖的地区”中覆盖最多的广播是maxKey=k1,将k1存储在一个集合broadcastsList中,并且将k1覆盖的“北京、上海、天津”地区从“未覆盖的地区”中移除,进行下一轮遍历
java实现贪心算法_第7张图片
反复按照上面方式进行遍历,当“未覆盖的地区”数为0时,得到的broadcastsList集合,便为最少的广播台,让所有的地区都可以接收到信号
在这里插入图片描述

代码

package ShangGuiGu.Algorithm.Greedy;

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>> broadcasts = new HashMap<>();
        //列出各个广播台所覆盖的地区
        HashSet<String> k1 = new HashSet<>();
        k1.add("北京");
        k1.add("上海");
        k1.add("天津");

        HashSet<String> k2 = new HashSet<>();
        k2.add("广州");
        k2.add("北京");
        k2.add("深圳");

        HashSet<String> k3 = new HashSet<>();
        k3.add("成都");
        k3.add("上海");
        k3.add("深圳");

        HashSet<String> k4 = new HashSet<>();
        k4.add("上海");
        k4.add("天津");

        HashSet<String> k5 = new HashSet<>();
        k5.add("杭州");
        k5.add("大连");
        
        broadcasts.put("k1",k1);
        broadcasts.put("k2",k2);
        broadcasts.put("k3",k3);
        broadcasts.put("k4",k4);
        broadcasts.put("k5",k5);

        //需要覆盖的地区
        HashSet<String> cities = new HashSet<>();
//        cities=getCities(broadcasts);
        cities.add("北京");
        cities.add("上海");
        cities.add("天津");
        cities.add("广州");
        cities.add("深圳");
        cities.add("成都");
        cities.add("杭州");
        cities.add("大连");

        //标记覆盖地区最多的广播台
        String maxKey=null;
        //存储“当前”广播台在“剩余”的地区中能覆盖的地区
        HashSet<String> tempSet = new HashSet<>();
        //存储每一次for循环,选取的广播台
        ArrayList<String> broadcastsList = new ArrayList<>();

        //当所有的地区都已经覆盖完,结束
        while (cities.size()!=0){
     

            for (String key:broadcasts.keySet()){
     
                //当前广播台覆盖的地区
                HashSet<String> curCities = broadcasts.get(key);
                //存储当前广播台覆盖的地区
                tempSet.addAll(curCities);
                //存储“当前”广播台在“剩余”的地区中能覆盖的地区==curCities与cities的交集
                tempSet.retainAll(cities);
                //检测到当前广播台包含的未覆盖的地区数量,比maxKey广播所包含的地区还多
                if (tempSet.size()>0&&(maxKey==null||tempSet.size()>broadcasts.get(maxKey).size())){
     
                    maxKey=key;
                }
                //清空当前广播台覆盖的地区,为下一次for循环
                tempSet.clear();
            }
            //选取到一个包含未覆盖地区最多的广播台
            if (maxKey!=null){
     
                broadcastsList.add(maxKey);
                //选取的广播已经覆盖了一部分未覆盖的地区,剩下的即为未覆盖的地区,用于下一次forEach循环
                cities.removeAll(broadcasts.get(maxKey));
            }
            //下一次wihle循环maxKey=null
            maxKey=null;
        }

        //打印选取的广播台
        System.out.println("选取的广播台:"+broadcastsList);
    }

    /**
     * 得到所有广播所覆盖的地区集合
     * @param broadcasts
     * @return
     */
    public static HashSet<String> getCities(HashMap<String,HashSet<String>> broadcasts){
     
        HashSet<String> cities = new HashSet<>();
        for (HashSet<String> curCities:broadcasts.values()){
     
            cities.addAll(curCities);
        }
        return cities;
    }
}

你可能感兴趣的:(数据结构与算法(java实现),java,数据结构,算法)