POJ 1375 Intervals

POJ 1375 Intervals

[★★☆☆☆]计算几何

  • 题目大意:

    在二维空间中,最上方一个点作为灯 ,下面有几个圆遮挡光线,求地面(x=0)上的阴影区间。

  • 输入格式:

    N(N个遮挡物,N=0时结束程序)
    bx, by(灯的坐标)
    N行:cxi, cyi, ri(遮挡物的坐标和半径)

  • 输出格式:

    阴影区间(从左到右输出,保留两位小数)

  • 样例

    输入:
    6
    300 450
    70 50 30
    120 20 20
    270 40 10
    250 85 20
    220 30 30
    380 100 100
    1
    300 300
    300 150 90
    1
    300 300
    390 150 90
    0

    输出:
    0.72 78.86
    88.50 133.94
    181.04 549.93

    75.00 525.00

    300.00 862.50

  • 解题思路:

    水题,除了推导公式的时候变量有一点多,稍微细心一点就没什么问题。
    首先对每个圆设切线坐标,根据切线到圆心距离等于半径解出直线方程,得到阴影区间。在此次注意直线设成 x = ay + x0 格式,避免了斜率不存在的情况,求直线与横坐标轴也特别方便(就是x0)。
    然后对得到的区间根据左边的x值进行排序。
    然后遍历区间数组,区间重叠就合起来,不重叠就输出。

  • 代码
#include <iostream>
#include <cmath>
#include <algorithm>

using namespace std;

const int MAXN = 500;

struct qujian{
    double qx, qy;
};

double lx, ly;
double cx[MAXN], cy[MAXN], r[MAXN];
//double a[MAXN][2];
qujian qj[MAXN];

double pf(double a) {
    return a*a;
}

bool comp(qujian t1, qujian t2) {
    return t1.qx < t2.qx;
}

//设直线 x = a * y + x0;
// x0 = lx - a*ly;
// 所以 x = a*y + lx - a*ly

int main() {
    int n;
    while (cin >> n) {
        if (n == 0) break;
        cin >> lx >> ly;
        for (int i = 0; i < n; i++) {
            cin >> cx[i] >> cy[i] >> r[i];
        }

        for (int i = 0; i < n; i++) {
            double ta, tb, tc, dt;
            double ans1, ans2;
            ta = (pf(cy[i]) + pf(ly) - 2*cy[i]*ly - pf(r[i]));
            tb = 2*(cy[i]*lx - cy[i]*cx[i] - lx*ly + ly*cx[i]);
            tc = (pf(lx) + pf(cx[i]) - 2*lx*cx[i] - pf(r[i]));
            dt = pf(tb) - 4*ta*tc;

            ans1 = (-tb - sqrt(dt))/(2*ta);
            ans2 = (-tb + sqrt(dt))/(2*ta);
//          a[i][0] = ans1; a[i][1] = ans2;

            qj[i].qx = lx - ans1*ly; qj[i].qy = lx - ans2*ly;
            if (qj[i].qx > qj[i].qy) swap(qj[i].qx, qj[i].qy);

        }
        sort(qj, qj+n, comp);

//      for (int i = 0; i < n; i++) {
//          cout << qj[i].qx << ' ' << qj[i].qy << endl;
//      }

        double nl, nr; // now_left, now_right
        nl = qj[0].qx; nr = qj[0].qy;
        for (int i = 1; i < n; i++) {
            if (qj[i].qx <= nr) {
                if (qj[i].qy > nr) nr = qj[i].qy;
            }
            else {
                printf("%.2lf %.2lf\n", nl, nr);
                nl = qj[i].qx; nr = qj[i].qy;
            }
        }
        printf("%.2lf %.2lf\n\n", nl, nr);


    }



    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值