问题描述

假设海岸线是一条无限延伸的直线,陆地在海岸线的一侧,海洋在另外一侧。每个小岛相当于海洋侧的一个点。坐落在海岸线上的基站只能覆盖半径为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 )

结果测试


编程实现

(如有错误欢迎指正!)
其中小岛坐标的排序参考了别人用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.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}public double getLeft() {return left;}public void setLeft(double left) {this.left = left;}
}
class S22 {//基站坐标private double x;private int y;public S22(double x, int y) {this.setX(x);this.setY(y);}public double getX() {return x;}public void setX(double x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}
}
class verify1{  //合理性检验private double tempC;private int tempX;private int tempY;private double tempD;private int flag;private int flagVer;public verify1(S2 S[],S22 C[],int d,int n,int m) {for(int i=0;i<n;i++) {tempX = S[i].getX();tempY = S[i].getY();flag = 0;for(int j=0;j<=m;j++) {tempC=C[j].getX();tempD=Math.sqrt((tempY * tempY + Math.pow((tempX - tempC), 2)));if(tempD>d) {flag = 0;}else{flag = 1;break;}}flagVer = flag + flagVer;}System.out.println("合理性验证结束");if(flagVer==n) {System.out.println("基站点能够覆盖所有岛屿");}else {System.out.println("基站点不能覆盖所有岛屿,请检查算法");}}
}public class IPDMinCircle {private static int n; // 岛数private int m; // 基站数public S22 C[] = new S22[n]; // 基站坐标private double c; // 基站横坐标private static int d; // 基站半径private int X1;private int Y1;private int tempX;private int tempY;private double tempD; // 小岛和旧圆心的距离public static int flag;public IPDMinCircle(S2 S[],int n,int d) {    X1 = S[0].getX();Y1 = S[0].getY();c = X1 + Math.sqrt(d * d - Y1 * Y1);C[0] = new S22(c,0);for (int j = 0; j < n; j++) {tempX = S[j].getX();tempY = S[j].getY();tempD = Math.sqrt((tempY * tempY + Math.pow((tempX - c), 2))); // 上一圆心位置,判断该岛坐标是否在上一圆内if ((tempD <= d)) { // 新岛坐标在旧圆内,即该岛位于旧圆内或圆上任意位置// 保留旧圆,不作新圆continue;} else if ((tempD > d)) { // 新岛坐标在旧圆外,即该岛位于旧圆心的右边且在圆外// 保留旧圆,另作新圆c = tempX + Math.sqrt(d * d - tempY * tempY);m = m + 1;C[m] = new S22(c,0);}}System.out.println(m+1);for (int i = 0; i <= m; i++) {System.out.println(C[i].getX() + " " + C[i].getY());}new verify1(S,C,d,n,m);}public static void main(String args[]) {Scanner in = new Scanner(System.in);System.out.println("请输入小岛数:");n = in.nextInt();System.out.println("请输入 基站半径:");d = in.nextInt();S2 S[] = new S2[n];System.out.println("请输入小岛坐标:");for (int i = 0; i < n; i++) {int k1 = in.nextInt();int k2 = in.nextInt();double tleft = Math.sqrt(d * d - k2 * k2) + k1 - d; S[i] = new S2(k1, k2, tleft);}for (int i = 0; i < n; i++) {if (Math.abs(S[i].getY()) > d) {flag = -1;System.out.println(flag);} else {flag = 1;}}if (flag > 0) {Arrays.sort(S, 0, n); // 排n个数,Arrays.sort(d)则默认排全部
//          for (int i = 0; i < n; i++) { //debug
//              System.out.println(S[i].getX()+" "+S[i].getY());
//          }new IPDMinCircle(S,n,d);}}
}

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

  1. 算法分析与设计 —— 贪心算法「活动安排」「背包问题」「哈夫曼编码」

  2. 基于哈夫曼编码对txt文档实现压缩处理 | 算法分析之贪心算法设计 C语言版

    声明:凡代码问题,欢迎在评论区沟通.承蒙指正,一起成长! 目录 一.实验内容与要求 二.概要设计 三.直接上代码 四.运行结果 一.实验内容与要求 内容:哈夫曼编码是广泛地用于数据文件压缩的十分有效的 ...

  3. leetcode1414. 和为 K 的最少斐波那契数字数目(贪心算法)

    给你数字 k ,请你返回和为 k 的斐波那契数字的最少数目,其中,每个斐波那契数字都可以被使用多次. 斐波那契数字定义为: F1 = 1 F2 = 1 Fn = Fn-1 + Fn-2 , 其中 n ...

  4. 设计测试用例实现语句覆盖,判定覆盖,条件覆盖,判定/条件覆盖,条件组合覆盖,路径覆盖.

    第一题: 设计测试用例实现语句覆盖,判定覆盖,条件覆盖,判定/条件覆盖,条件组合覆盖,路径覆盖. [1]语句覆盖(设计若干个测试用例,使程序中的每个可执行语句至少执行一次) (x>3)& ...

  5. 算法分析与设计:贪心算法实现最少硬币找钱问题(支付+找零共花费硬币数最少)

    硬币找钱问题 Problem Description 设有六种不同面值的硬币,各硬币的面值分别为 5分,1角,2角,5角,1元,2元.现要用这些面值的硬币来购物和找钱.购物时可以使用的各面值的硬币个数 ...

  6. 三十六、贪心算法--集合覆盖问题

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

  7. 【算法笔记】:区间覆盖问题:贪心算法

    证明贪心算法的正确性: 下面证明: (1)最优子结构: 假设结果有n个区间,去掉最后一个区间及对应的点,则前n-1个区间仍然是覆盖所有点的所用的最少区间(最优解的子结构是子问题的最优解) 证明: cu ...

  8. c语言学生成员管理代码报告怎么写,C语言学生通信录管理系统课程设计报告

    <C语言学生通信录管理系统课程设计报告>由会员分享,可在线阅读,更多相关<C语言学生通信录管理系统课程设计报告(18页珍藏版)>请在人人文库网上搜索. 1.实验名称 :学生通信 ...

  9. 贪心算法【区间调度】【背包问题】【集合覆盖】【旅行商问题】【哈夫曼构造价值树】

    贪心算法  在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解.  贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择, ...

最新文章

  1. 第5关:32位快速加法器设计
  2. Smart Form不弹出假脱机设置界面直接打印预览
  3. 【CyberSecurityLearning 57】XSS
  4. C语言(初遍学的一些零乱笔记)
  5. HTML+CSS+JS实现 ❤️仿切水果小游戏❤️
  6. 定时器时间动态变化(变速)
  7. swoole实现Timer定时器、心跳检测及Task进阶实例:mysql连接池
  8. node2vec的一些理解
  9. 基于java校园教务排课系统设计与实现(springboot框架)
  10. 二进制和十六进制的转换操作
  11. PB程序中在普通激光打印机上实现条码打印
  12. 什么是DQL,DML,DDL,DCL
  13. 跟着团子学SAP PS:增加WBS元素为分摊发送方提升单个项目内部成本精准归集 KSV1/KSU1
  14. Winform的内容
  15. 迪桑特宣布彭于晏成为品牌代言人
  16. 搜索推荐系统中的召回
  17. linux系统中的挂载有什么用,linux 挂载详解
  18. 手机二要素认证接口怎么用?手机号姓名验证怎么操作?
  19. 智力题解题报告 No.3 计算24点
  20. 在Ubuntu环境下使用docker配置webgoat环境

热门文章

  1. 朗科实习期间心得笔记(五)
  2. 第十二届北航程序设计竞赛初赛——勾肥大战题解
  3. 淘宝技术牛p博客整理
  4. 微型计算机最早出现在1946年是对还是错,2016年计算机一级期末考试真题(含答案)...
  5. Nodejs获取客户端IP
  6. 百度云OSS云存储上传及获取
  7. 24GHz道闸防砸雷达传感器SRR189 winfrom 调试小程序
  8. 机器视觉——OpenCV案例分析基础(二)(给图片打马赛克与图像的运算处理)
  9. 失望,太失望了北京奥运男子110米栏第1轮 刘翔旧伤复发退赛
  10. Unity动态更换APP图标及名称