POJ1328Radar Installation贪心+模拟队列+结构体排序+运算符重载+构造函数

POJ1328 Radar Installation 雷达安装 贪心+模拟队列+结构体排序+运算符重载+构造函数

标签(空格分隔): 算法竞赛 C++ 算法


这道题用到的是贪心算法,但是牵扯到了很多c++语法知识,所以我花了很长时间去学习相关语法。
题目中用到的语法有(包括但不限于):结构体的构造函数、运算符重载、结构体的排序函数、队列数据结构的模拟。
一开始我想的很简单,只需要每次考虑所在位置最高(纵坐标最大)的点的坐标,以它在x轴的横坐标点为圆心花一个个圆即可;如果y轴坐标相同,就从x轴坐标小的开始。但是这样做不对,数量会偏大,画个图就可以明白过来(但我当时也没想明白,直到看了别人的答案才搞明白)。后来看到别人的解析,才发现这是一个区间取点问题,这才做出来的。

具体思路是这样的:既然我们要找到最少的雷达安装数,也就是找到圆心在x轴,半径固定为常数d的圆的最小数目,那么我们先以每一个小岛为圆心,d为半径做圆,找到每一个圆与x轴相交形成的长度区间,将这些区间构成一个集合。之后,再找出最小数目的点,使这些点恰好被所有的区间包含。找出最少点这一步,我采用了区间重排后取并集的算法。按区间的上界非降排序后,answer+1,从第一个区间a1和第二个区间a2开始取交集。如果有交集,就将交集赋给原先的排头a1,a1出队,即排头后移一位,再对a1和a3取交集,直到没有交集,就跳出循环。answer+1,再从这时候的排头开始这种循环。

题目我就不打了,直接上代码。

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
typedef struct _pair    //构造结构体_pair,存储每一个小岛形成的区间
{
    double a;
    double b;
    _pair(double x=0,double y=0) {a=x,b=y;};        //定义构造函数,方便变量初始化结构体
    //bool operator < (const _pair c)const {return b<c.b;}        //在结构体内重载运算符“<”,使得sort函数排序时能按照结构体的元素排序。
}_pair;
_pair que[1000+5];      //存储每一个长度区间的集合
int head,tail;          //顾名思义,分别为队列的头部和尾部下标
bool cmp(_pair a1,_pair a2)     //定义结构体的排序函数。如果line10的运算符重载没有被注释,那么可以去掉下面line54中的cmp,此时这一步就不需要了。重载被注释时,就需要这个比较函数了。若区间为[a,b)的形式,它意为先按b从小到大排列,b相同的区间,按a从大到小排列。这样的话,长度较短、位置靠前的区间就始终在队列的前部。
{
    if (a1.b==a2.b)
    {
        if (a1.a==a2.a)
            return true;
        else
            return a1.a>a2.a;
    }
    else
        return a1.b<a2.b;
}
bool judge(_pair &t,_pair v)        //此处为最重要的区间取交集函数,但是原理不复杂。
{
    if (t.b>=v.a&&t.a<=v.b)
    {
        t.a=max(t.a,v.a);
        t.b=min(t.b,v.b);
        return true;
    }
    return false;
}
//inline 是“内联命令”,相当于对函数的宏定义,下次每次碰到被内联定义的该函数,编译器都会用这里的函数替换它,而不是发生控制转移。
inline void _push(_pair c)  {que[tail]=c;tail++;}       //模拟入队操作
inline void _pop()  {head++;}           //模拟出队操作
int main()
{
    int n,d,t=0,ans=0;
    while (scanf("%d%d",&n,&d)&&(n||d))
    {
        int n0=n,flag=0;
        t++;
        ans=head=tail=0;
        while (n0--)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            if (y>d)    flag=1;
            _push(_pair(x-sqrt((double)d*d-y*y),x+sqrt((double)d*d-y*y)));  //这一步当时我看了很久,才明白这是用构造函数初始化了一个_pair型数据,将它入队。当该循环执行完成后,tail就到了队尾。
        }
        if (flag==1)    {printf("Case %d: -1\n",t);continue;}
        sort(que,que+n,cmp);        
        while (head!=tail)
        {
            ans++;
            _pair t=que[head];
            while (head!=tail)
            {
                _pair v=que[head];
                if (judge(t,v)) _pop();     //显然,此处第一次执行是对同一个区间求交集,但是并不影响最终结果
                else break;
            }
        }
        printf("Case %d: %d\n",t,ans);
    }
    return 0;
}

刚开始以为是很简单的一道题,结果一做做了一天。期间也确实学到了很多有用的东西,收获很大。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值