poj1328题解

//题目思路
//将每个小岛坐标作为圆心
//以雷达探测半径d画一个圆然后,然后这个圆和X轴的两个交点
//这两个交点构成一段线段
//即有两个端点(即这个圆和X轴的两个交点)
//设置为左右两个端点
//所以每个小岛的坐标都会有左右两个端点(如果当前点满足条件(即当前小岛的纵坐标小于或等于一开始录入的雷达半径))
//因为如果当前小岛的纵坐标大于一开始录入的雷达半径(即以当前小岛坐标为圆心画的圆不会和X轴有交点)(自然不满足题目条件要求的,所有的雷达要探测到所有的小岛)
//即可以打印-1
//Memory 176K Time 32MS
#include <bits/stdc++.h>

using namespace std;

//按点集(即对应的小岛坐标画一个圆对应的X轴截取的线段)的左端点从小到大排序
bool cmp(pair<double, double> a, pair<double, double> b) {
    return a.first < b.first;
}

int main() {
    int n;//点集个数即小岛个数
    double d;//雷达半径
    int now = 1;//当前方案的序号

    //录入小岛个数和雷达半径
    while (scanf("%d%lf", &n, &d)) {
        //结束循环条件
        if (n == 0 && d == 0)
            break;

        //记录是否当前方案有解
        //默认true为有解
        bool flag = true;
        //录入n个点集
        pair<double, double> p[1010];
        for (int i = 0; i < n; i++) {
            double x, y;
            //录入每个小岛的坐标
            scanf("%lf%lf", &x, &y);

            //当前小岛的纵坐标大于雷达半径,即安装多少个雷达都不能探测到所有的小岛
            if (fabs(y) > d)
                flag = false;
            else
                //记录当前小岛的坐标(初始化为X轴的区间)
                p[i] = make_pair(x - sqrt(d * d - y * y), x + sqrt(d * d - y * y));
        }

        //当前方案没有解
        if (!flag)
            printf("Case %d: -1\n", now);
        else {
            //计算区间
            //排序点集区间
            sort(p, p + n, cmp);
            pair<double, double> temp = p[0];
            int count = 1;//记录至少需要使用的雷达数量
            //遍历剩余小岛
            for (int i = 1; i < n; i++)
                //当前小岛的左端点大于temp的右端点
                //即当前小岛和temp小岛没有共同的区间(没有交集)
                //即需要至少两个雷达才能探测到这两个小岛
                if (p[i].first > temp.second)
                    count++, temp = p[i];
                    //当前遍历小岛包含于temp小岛
                    //即当前小岛和temp小岛可以共用一个雷达(用一个雷达就可以探测到这两个小岛所以count不进行加1)
                else if (p[i].second < temp.second)
                    temp = p[i];

            printf("Case %d: %d\n", now, count);
        }
        //方案数进行加1
        now++;

    }

    return 0;
}

//简洁版
#include <bits/stdc++.h>

using namespace std;

bool cmp(pair<double, double> a, pair<double, double> b) {
    return a.first < b.first;
}

int main() {
    int n;
    double d;
    int now = 1;

    while (scanf("%d%lf", &n, &d)) {
        if (n == 0 && d == 0)
            break;

        bool flag = true;
        pair<double, double> p[1010];
        for (int i = 0; i < n; i++) {
            double x, y;
            scanf("%lf%lf", &x, &y);

            if (fabs(y) > d)
                flag = false;
            else
                p[i] = make_pair(x - sqrt(d * d - y * y), x + sqrt(d * d - y * y));
        }

        if (!flag)
            printf("Case %d: -1\n", now);
        else {
            sort(p, p + n, cmp);
            pair<double, double> temp = p[0];
            int count = 1;
            for (int i = 1; i < n; i++)
                if (p[i].first > temp.second)
                    count++, temp = p[i];
                else if (p[i].second < temp.second)
                    temp = p[i];

            printf("Case %d: %d\n", now, count);
        }
        now++;

    }

    return 0;
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值