最少圆覆盖通信覆盖问题-算法分析设计-贪心算法-java实现

问题描述

假设海岸线是一条无限延伸的直线,陆地在海岸线的一侧,海洋在另外一侧。每个小岛相当于海洋侧的一个点。坐落在海岸线上的基站只能覆盖半径为d的范围。应用直角坐标系,将海岸线作为x轴,设海洋侧在x轴上方。给定海洋中各小岛的位置,以及通信基站的覆盖半径,要求用最少的基站覆盖所有小岛,使得每个小岛都能和陆地通过某基站通信(在某个基站覆盖范围内)。
输入:小岛数目,基站覆盖半径,各小岛坐标
输出:覆盖小岛的最少基站数目及基站坐标,如果无解,输出-1.
问题描述

问题分析

因为每一个基站点都在x坐标上,每个基站的通信覆盖区域都为固定半径的圆,所以容易知道y坐标绝对值小于该固定半径的小岛一定能被覆盖。
而要想实现用最少的基站(最少的圆)覆盖这些小岛,即基站覆盖的小岛数要尽量多,没有多余的基站,容易想到该问题与最少线段覆盖点非常类似,只是最少线段覆盖点问题是一维的,而最少圆覆盖是二维的,但贪心求解原理都相同。都是将小岛坐标从左至右(或从右至左)排列,逐一画圆并判断覆盖区域范围,但是最少圆覆盖问题的排序,应该是以小岛坐标为圆上一点时能覆盖的左区间从左至右排序更为准确。
最少圆覆盖坐标排序如上图,输入小岛坐标S=[S2,S1,S4,S3],按照以各点为圆上一点时能覆盖的左区间从左至右(从小到大)排序后得到S=[S1,S2,S3,S4]。开始作圆,
从左至右,从S1开始,即先画出黄圈,到S2,因为S2在上一圆内,故继续;到S3,因S3在上一圆(黄圈)外,故保留上一圆(黄圈),另作新圆(蓝圈),到S4,因S4在上一圆(蓝圈)内,故继续。
否则,如果只是按照x坐标从左至右排序,即从S2开始作圆,到S1,S1并不在S2所作的红圈内,故作新圆,如此产生多余的圆。

求解思路

以各小岛坐标为半径为d的圆上一点时能覆盖的左区间,按从小到大排序得S集合,从S中依次考察点S[i]的位置,若S[i]不在上一圆C[j]内,则以该坐标为圆上一点、d为半径作新圆C[j+1],直到S中所有坐标考察完为止。
方法:

  1. if 输入的纵坐标大于基站半径d
  2. then return -1 exit
  3. else 按各坐标的左区间从小到大排序得S
  4. C[0]= X0 + sqrt(d * d – Y0 * Y0);
  5. for i←1 to n do
  6. if S[i]不在圆内
  7. then c = S[i].x + sqrt(d * d – S[i].y * S[i].y);
  8. then C←C∪{c}
  9. return C

算法正确性证明

(自己写的可能不太准确)
命题:对输入任何规模为n的输入实例,算法得到最少基站数;
归纳基础:证明对任何只有1个小岛(纵坐标小于基站半径)的输入实例,贪心法得到最优解,S中只有一个岛,则C中只有一个基站,最少基站集合就是C,显然正确;
归纳步骤:证明:假设对于任何n个小岛的输入实例贪心法都能得到最优解,那么对于任何n+1个小岛的输入实例,贪心法也得到最优解;
考虑输入N={1,2,…,n+1},已排序
由归纳假设,对于N’={2,3,…,n+1},
贪心法得到最优解I’,另I=I’∪{1}({1}表示只覆盖第1个小岛的基站)
若不然,存在包含1的关于N的最优解I^(1表示达到最左区间的坐标),且|I |>|I|;那么I*-{1}是N’和C’的解且|I^*-{1}|>|I-{1}|=|I’|,与I’是关于N’和C’的最优解矛盾。

复杂性计算

排序算法执行O(n log⁡n))次,贪心算法执行O(n)时间,总的算法时间T(n)=O(n log⁡n )

结果测试

测试1
测试2

编程实现

(如有错误欢迎指正!)
其中小岛坐标的排序参考了别人用Comparable接口实现Array排序的方法,没有手写排序算法。

package minCirlcle;
import java.util.Arrays;
import java.util.Scanner;

class S2 implements Comparable<S2> {
   	//小岛坐标及左区间
	private int x;
	private int y;
	private double left;
	public S2(int x, int y, double left) {
   
		this.setX(x);
		this.setY(y);
		this.setLeft(left);
	}
	public int compareTo(S2 s) {
   
		return (int) (this.getLeft() - s.left);
	}
	public int getX() {
   
		return x;
	}
	public void setX(int x) {
   
		this
  • 9
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值