贪心算法解决集合覆盖问题

问题描述:

假设存在下面需要付费的广播台,以及广播台需要覆盖的地区,如何选择最少的广播台,让所有的地区都可以接受到信号.

广播台覆盖地区
k1“北京”,“上海,“天津””
k2“广州”,“北京,“深圳””
k3“成都”,“上海,“杭州””
k4“上海,“天津””
k5“杭州”,“大连”"
k6“福州”,“重庆”"

贪心算法:

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。

解决思路:

1.添加覆盖地区,并构建广播站

    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("大连");

    HashSet<String> hashSet6 = new HashSet<>();
    hashSet6.add("福州");
    hashSet6.add("重庆");

    //构建广播台
    HashMap<String, HashSet<String>> broadcasts = new HashMap<>();
    broadcasts.put("k1", hashSet1);
    broadcasts.put("k2", hashSet2);
    broadcasts.put("k3", hashSet3);
    broadcasts.put("k4", hashSet4);
    broadcasts.put("k5", hashSet5);
    broadcasts.put("k6", hashSet6);

`

2.构建存放所有需要覆盖的地区的集合,每添加一个广播站就要从该集合中清除对应的地区;

 //存放所有需要覆盖的地区
        HashSet<String> allAreas = new HashSet<>();
        for (Set<String> areas : broadcasts.values()) {
            //只能addAll,add会出现[“北京”,“上海,“天津””][“广州”,“北京,“深圳””]按照集合的形式存在会有重复
            allAreas.addAll(areas);
        }

3.遍历广播站每次找出能覆盖待覆盖区域数最多的广播站,这一步就是贪心算法的体现,局部最优

完整java代码实现:

package com.yg.algorithm;/*
@author  Mu_Mu
@date    2020/3/19  10:15
*/

import java.util.*;

public class GreedyAlogorithm {
    public static void main(String[] args) {
        //添加覆盖地区
        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("大连");

        HashSet<String> hashSet6 = new HashSet<>();
        hashSet6.add("福州");
        hashSet6.add("重庆");

        //构建广播台
        HashMap<String, HashSet<String>> broadcasts = new HashMap<>();
        broadcasts.put("k1", hashSet1);
        broadcasts.put("k2", hashSet2);
        broadcasts.put("k3", hashSet3);
        broadcasts.put("k4", hashSet4);
        broadcasts.put("k5", hashSet5);
        broadcasts.put("k6", hashSet6);

        //存放所有需要覆盖的地区
        HashSet<String> allAreas = new HashSet<>();
        for (Set<String> areas : broadcasts.values()) {
            //只能addAll,add会出现[“北京”,“上海,“天津””][“广州”,“北京,“深圳””]按照集合的形式存在会有重复
            allAreas.addAll(areas);
        }

        //存放需要选择的广播站列表
        ArrayList<String> broadList = new ArrayList<>();
        //maxKey代表能覆盖待覆盖区域最大的广播站
        String maxKey = null;
        int maxNum = 0;//能覆盖待覆盖区域最大的数量
        //只要allAreas.size() >0说明还有地区需要被覆盖
        //存放能覆盖待覆盖的区域
        HashSet<String> tempSet = new HashSet<>();
        while (allAreas.size() > 0) {
            maxKey = null;
            for (String key : broadcasts.keySet()) {
                tempSet.clear();
                tempSet.addAll(broadcasts.get(key));
                tempSet.retainAll(allAreas);
                if (tempSet.size() > 0 && (maxKey == null || tempSet.size() > maxNum)) {
                    maxKey = key;
                    maxNum = tempSet.size();
                }
            }
            if (maxKey != null) {
                broadList.add(maxKey);
                //从待覆盖区域的集合中移除这次新增覆盖区域
                allAreas.removeAll(broadcasts.get(maxKey));
            }
        }
        System.out.println("待添加的广播站有:");
        for (String str : broadList) {
            System.out.print(str+" ");
        }

    }
}


  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
区间覆盖问题是指在一条数轴上,给定若干个区间,选取尽可能少的区间,使得这些区间能够覆盖整个数轴。贪心算法是一种自下而上的贪心策略,每次选择能够覆盖尽可能多未被覆盖区域的区间加入解集合中。 具体算法步骤如下: 1. 将所有区间按照右端点从小到大排序。 2. 初始化当前右端点为负无穷。 3. 遍历所有区间,对于每个区间: a. 如果当前右端点小于等于该区间的左端点,将该区间加入解集合中,更新当前右端点为该区间的右端点。 4. 返回解集合。 算法时间复杂度为O(nlogn),其中n为区间个数。以下是Python实现: ```python def interval_cover(intervals): intervals.sort(key=lambda x: x[1]) # 按右端点排序 right = float('-inf') # 初始化当前右端点 chosen = [] # 解集合 for interval in intervals: if right <= interval[0]: # 如果当前右端点小于等于该区间的左端点 chosen.append(interval) # 将该区间加入解集合中 right = interval[1] # 更新当前右端点为该区间的右端点 return chosen ``` 其中,intervals是一个包含区间左右端点的列表,如[(1, 3), (2, 4), (3, 5), (4, 6)]。函数返回一个解集合,如[(1, 3), (3, 5), (4, 6)],它们能够覆盖整个数轴。 该算法的正确性可以通过反证法证明。假设存在一个更优的解集合S',但该解集合与算法得到的解集合S不同,也就是说它们至少有一个区间不同。我们可以假设在S中覆盖最左边的未被覆盖区域时选择了一个区间I1,而在S'中覆盖同一区域时选择了另一个区间I2。由于I2的右端点在I1的右端点右侧,所以I2能够覆盖的未被覆盖区域一定比I1小,因此在S中选择I1比选择I2更优。这与假设矛盾,因此S即为最优解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值