贪心算法解决最少圆覆盖最多点问题

     贪心算法解决最少圆覆盖最多点问题  

     海面上有一些船需要与陆地进行通信,需要在海岸线上布置一些基站。现将问题抽象为,在x轴上方,给出N条船的坐标 ,在x轴上安放的基站可以覆盖半径为d的区域内的所有点,问在x轴上至少要安放几个点才可以将x轴上方的点都覆盖起来。试设计一个算法求解该问题,并分析算法的正确性。

《贪心算法解决最少圆覆盖最多点问题》

解:

设计思路:

首先将所有的点按横坐标升序排序。

点集非空时,每次取出横坐标最小的点,将该点视做左半圆周上的点,取距离该点横坐标为d的x轴上的点作为圆心,从圆心处以d为半径作圆(圆心坐标在该点坐标右侧),然后去除掉包含在该圆内的点。然后继续选出剩下点中横坐标最小的点,重复以上操作,直至将所有点包括到圆中,表示所有点都被覆盖,此时得出的圆的个数就是该问题的最优解。

先把点按X轴排序 求出能覆盖每条船的点在X轴上的区间。从最左边的点开始,如果下一个点的左区间比现在的右区间还大,就要新的基站;如果下一个的右区间小于现在的右区间,需要将现在的右区间更新为小的,因为必须覆盖所有点。

如果新圆心的坐标在前一个圆心坐标左侧,那么就舍弃前一个圆心坐标,相反,则表明该圆心成立,通过这种方法,可以使一个圆尽可能覆盖周围的点,局部最优,重复每次操作,则满足全局最优

最优子结构性质:

《贪心算法解决最少圆覆盖最多点问题》

贪心选择性:

《贪心算法解决最少圆覆盖最多点问题》

// Test.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
struct Node
{
    double l;//最左可被覆盖的坐标
    double r;//最右可被覆盖的坐标
};
Node a[1010];
int i,j,k,n,m;
double d,x,y;
int ans;//结果
const double ZERO=1e-8;//控制精度


bool cmp(Node a,Node b)//最左可被覆盖的坐标排序,从左到右排序
{
    if (a.l<b.l) return 1;
    return 0;
}

void Greedy()
{
    double now=a[0].r;
    ans++;
    for (int i=1;i<n;i++)
    {
        if (a[i].l>now+ZERO)//下个点的最左被覆盖的坐标大于当前最右可被覆盖坐标
        {
            ans++;
            now=a[i].r;
        }else if (a[i].r<now+ZERO)//下个点的最左被覆盖的坐标小于当前最右可被覆盖坐标
        {
            now=a[i].r;
        }

    }
}

int main()
{
    printf("输入覆盖半径d:\n");
    cin>>d;
    printf("输入船的数量n:\n");
    cin>>n;
    printf("输入n条船的坐标:\n");

    for(int i=0;i<n;i++)
    {
        cin>>x>>y;
        double len=sqrt((double)(d*d-y*y));//勾股定理
        a[i].l=x-len;//计算最左可被覆盖的坐标
        a[i].r=x+len;//计算最右可被覆盖的坐标
    }
    sort(a,a+n,cmp);
    ans=0;
    Greedy();
    printf("在x轴上至少要安放%d个点才可以将所有点覆盖\n",ans);
    return 0;
}
    原文作者:贪心算法
    原文地址: https://blog.csdn.net/WilsonSong1024/article/details/79449536
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞