POJ 1375 Intervals【过定点做圆的切线】

76 篇文章 0 订阅
24 篇文章 0 订阅

链接:



Intervals
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 3675 Accepted: 1056

Description

In the ceiling in the basement of a newly open developers building a light source has been installed. Unfortunately, the material used to cover the floor is very sensitive to light. It turned out that its expected life time is decreasing dramatically. To avoid this, authorities have decided to protect light sensitive areas from strong light by covering them. The solution was not very easy because, as it is common, in the basement there are different pipelines under the ceiling and the authorities want to install the covers just on those parts of the floor that are not shielded from the light by pipes. To cope with the situation, the first decision was to simplify the real situation and, instead of solving the problem in 3D space, to construct a 2D model first. 
Within this model, the x-axis has been aligned with the level of the floor. The light is considered to be a point light source with integer co-ordinates [bx,by]. The pipes are represented by circles. The center of the circle i has the integer co-ordinates [cxi,cyi] and an integer radius ri. As pipes are made from solid material, circles cannot overlap. Pipes cannot reflect the light and the light cannot go through the pipes. You have to write a program which will determine the non-overlapping intervals on the x-axis where there is, due to the pipes, no light from the light source. 

Input

The input consists of blocks of lines, each of which except the last describes one situation in the basement. The first line of each block contains a positive integer number N < 500 expressing the number of pipes. The second line of the block contains two integers bx and by separated by one space. Each of the next N lines of the block contains integers cxi, cyi and ri, where cyi + ri < by. Integers in individual lines are separated by one space. The last block consists of one line containing n = 0.

Output

The output consists of blocks of lines, corresponding to the blocks in the input(except the last one). One empty line must be put after each block in the output. Each of the individual lines of the blocks in the output will contain two real numbers, the endpoints of the interval where there is no light from the given point light source. The reals are exact to two decimal places and separated by one space. The intervals are sorted according to increasing x-coordinate.

Sample Input

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

Sample Output

0.72 78.86
88.50 133.94
181.04 549.93

75.00 525.00

300.00 862.50

Source




算法: 计算几何  定点做圆的切线 向量的旋转



题意:


天花板上有一个点, 下面有 N 个圆
过天花板上的这个点,做这些圆的切线,那么就会在地板上留下阴影部分
按从左到右输出所有的阴影部分。
注意: 要合并重叠的
           cyi + ri < by 圆一定在天花板下面.

思路:


由题目可以知道, 圆一定在天花板下面, 所以说,定点一定能对每个圆画出两条切线.
那么我们只要确定了切线,这条直线和 X 轴的交点还是很好确立的。


如何确立切线

1.先求出定点 Ceil 到圆心 C 的方向向量 U .【已知两个确定的点求方向 U = C - Ceil】
2.再根据圆的切线性质求出:切线相对于 U 的偏转角度 a 【sin(a) = r / Length(u)】不懂的自己画图很容易理解的。。。
                                                   从而可以得到角度 a 的弧度值 用反三角函数 asin() 即可。
3.令 2 中求出的弧度值为 ang 
   那么方向向量 U 顺时针旋转 rad 就可以得到第一条切线,确立阴影的起始位置
   逆时针旋转 rad 就可以得到第二条切线, 确立阴影的结束位置。
   已知一条直线的方向和线上一定点 , 求其与 X 轴的交点还是很好处理的吧。


关于向量的旋转这里套用向量旋转公式:证明见:点击打开链接
//rad是弧度
//向量 A 逆时针旋转 rad
Vector Rotate(Vector A, double rad) {
    return Vector(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad));
}

已知一条直线的方向 V 和线上一定点 P  , 求其与 X 轴的交点
个人理解还是根据点斜式处理比较好了,但是这里的斜率不是  K = V.y / V.x 而是  k1 = V.x / V.y
因为所求的切线可能会垂直于 X 轴, 那么这样的斜率就没有意义,同时点斜式写成  x = k1*y + b1
那么 b1 就是与 X 轴的交点, 直接返回即可。
//知道直线方向向量,方向和定点,求与 X 轴的交点,返回交点的横坐标值
double PointOfSkewToPoint(Vector V, Point P) {
    double k1 = V.x / V.y; //斜率的倒数 ,方便处理了垂直于 X 轴的情况 x = ky +b;
    double b1 = P.x - k1*P.y; // 与 X 轴的交点

    return b1;
}

PS:关于点斜式:如果直线有垂直于 X 轴的情况就用  x = k1*y + b1
                        如果直线有垂直于 Y 轴的情况就用  y = k*x + b
                        如果两种情况都可能出现,那么遇到具体问题怎么好处理再具体分析把。

很裸的题目了,也是本弱菜第一个关于圆的几何题目.


注意:


输出的时候线段合并的处理。这里本人贡献一次 WA ,具体代码中标示了,这里不再赘述。感谢 肖煌宇 同学的提醒.

关于 POJ 的 double 型提交问题:贡献一次 OLE (Out Limit Exceed)
POJ : double 的输出如果用 G++ 提交就要用 %f 否则会 OLE
                   如果用 C++ 提交则不会产生这样的问题。
HDU 则完全不会出现上述问题。【提醒来自 kuangbin 大神】


code:

1375Accepted136K32MSC++2705B

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
using namespace std;

const int maxn = 510;
int n;

struct Point {
    double x,y;
    Point() {}
    Point(double _x, double _y) {
        x = _x; y = _y;
    }

    Point operator - (const Point &b) const {
        return Point(x-b.x, y-b.y);
    }
    double operator *(const Point &b) const {
        return x*b.x + y*b.y;
    }
    double operator ^(const Point &b) const {
        return x*b.y - y*b.x;
    }

}Ceil;

typedef Point Vector;

//rad是弧度
//向量 A 逆时针旋转 rad
Vector Rotate(Vector A, double rad) {
    return Vector(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad));
}
//计算向量极角
double angle(Vector V ) {
    return atan2(V.y, V.x);
}
double Length(Vector V) {
    return sqrt(V.x*V.x+V.y*V.y);
}

struct Circle {
    Point c;
    double r;
    Circle() {}
    Circle(Point _c, double _r) {
        c = _c; r = _r;
    }
    Point point(double a) { // a 为相对于 X 轴的正方向逆时针偏转角度
        return Point(c.x+cos(a)*r, c.y+sin(a)*r);
    }
}circle;

struct Node{
    double st,en;
}ans[maxn];

const double eps = 1e-5;
int dcmp(double x) {
    if(x < eps) return 0;
    else return x < 0 ? -1 : 1;
}

//知道直线方向向量,方向和定点,求与 X 轴的交点,返回交点的横坐标值
double PointOfSkewToPoint(Vector V, Point P) {
    double k1 = V.x / V.y; //斜率的倒数 ,方便处理了垂直于 X 轴的情况 x = ky +b;
    double b1 = P.x - k1*P.y; // 与 X 轴的交点

    return b1;
}
//处理第 index 个圆, 计算其在 X 轴产生的阴影部分
void Tangents(int index) {
    Circle C = circle;

    Vector u = C.c - Ceil;
    double distance = Length(u);

    double ang = asin(C.r / distance);
    Vector v1 = Rotate(u, -ang); //st
    Vector v2 = Rotate(u, +ang); //en

    ans[index].st = PointOfSkewToPoint(v1, Ceil);
    ans[index].en = PointOfSkewToPoint(v2, Ceil);
}

bool cmp(Node a, Node b) {
    return (a.st == b.st && a.en <= b.en) || a.st < b.st;
}

int main()
{
    while(scanf("%d", &n) != EOF) {
        if(n == 0) break;
        double x,y,r;
        scanf("%lf%lf", &x,&y); Ceil = Point(x, y);

        for(int i = 0; i < n; i++) { //边输入边处理每一个圆
            scanf("%lf%lf%lf", &x, &y, &r);
            circle = Circle(Point(x, y), r);
            Tangents(i);
        }

        sort(ans, ans+n, cmp);

        int index = 0;
        for(int i = 1; i < n; i++) { //合并重叠的
            if(ans[i].st <= ans[index].en) ans[index].en = max(ans[index].en, ans[i].en); //注意:是取二者中较大的, 而不是 ans[i].en, 贡献一次WA
            else ans[++index] = ans[i];
        }

        for(int i = 0; i <= index; i++)
            printf("%.2lf %.2lf\n", ans[i].st, ans[i].en);
        printf("\n");

    }
    return 0;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
㈠ 点的基本运算 1. 平面上两点之间距离 1 2. 判断两点是否重合 1 3. 矢量叉乘 1 4. 矢量点乘 2 5. 判断点是否在线段上 2 6. 求一点饶某点旋转后的坐标 2 7. 求矢量夹角 2 ㈡ 线段及直线的基本运算 1. 点与线段的关系 3 2. 求点到线段所在直线垂线的垂足 4 3. 点到线段的最近点 4 4. 点到线段所在直线的距离 4 5. 点到折线集的最近距离 4 6. 判断是否在多边形内 5 7. 求矢量夹角余弦 5 8. 求线段之间的夹角 5 9. 判断线段是否相交 6 10.判断线段是否相交但不交在端点处 6 11.求线段所在直线的方程 6 12.求直线的斜率 7 13.求直线的倾斜角 7 14.求点关于某直线的对称点 7 15.判断两条直线是否相交及求直线交点 7 16.判断线段是否相交,如果相交返回交点 7 ㈢ 多边形常用算法模块 1. 判断多边形是否简单多边形 8 2. 检查多边形顶点的凸凹性 9 3. 判断多边形是否凸多边形 9 4. 求多边形面积 9 5. 判断多边形顶点的排列方向,方法一 10 6. 判断多边形顶点的排列方向,方法二 10 7. 射线法判断点是否在多边形内 10 8. 判断点是否在凸多边形内 11 9. 寻找点集的graham算法 12 10.寻找点集凸包的卷包裹法 13 11.判断线段是否在多边形内 14 12.求简单多边形的重心 15 13.求凸多边形的重心 17 14.求肯定在给定多边形内的一个点 17 15.求从多边形外一点出发到该多边形的切线 18 16.判断多边形的核是否存在 19 ㈣ 的基本运算 1 .点是否在内 20 2 .求不共线的三点所确定的 21 ㈤ 矩形的基本运算 1.已知矩形三点坐标,求第4点坐标 22 ㈥ 常用算法的描述 22 ㈦ 补充 1.两关系: 24 2.判断是否在矩形内: 24 3.点到平面的距离: 25 4.点是否在直线同侧: 25 5.镜面反射线: 25 6.矩形包含: 26 7.两交点: 27 8.两公共面积: 28 9. 和直线关系: 29 10. 内切: 30 11. 求切点: 31 12. 线段的左右旋: 31
㈠ 点的基本运算 1. 平面上两点之间距离 1 2. 判断两点是否重合 1 3. 矢量叉乘 1 4. 矢量点乘 2 5. 判断点是否在线段上 2 6. 求一点饶某点旋转后的坐标 2 7. 求矢量夹角 2 ㈡ 线段及直线的基本运算 1. 点与线段的关系 3 2. 求点到线段所在直线垂线的垂足 4 3. 点到线段的最近点 4 4. 点到线段所在直线的距离 4 5. 点到折线集的最近距离 4 6. 判断是否在多边形内 5 7. 求矢量夹角余弦 5 8. 求线段之间的夹角 5 9. 判断线段是否相交 6 10.判断线段是否相交但不交在端点处 6 11.求线段所在直线的方程 6 12.求直线的斜率 7 13.求直线的倾斜角 7 14.求点关于某直线的对称点 7 15.判断两条直线是否相交及求直线交点 7 16.判断线段是否相交,如果相交返回交点 7 ㈢ 多边形常用算法模块 1. 判断多边形是否简单多边形 8 2. 检查多边形顶点的凸凹性 9 3. 判断多边形是否凸多边形 9 4. 求多边形面积 9 5. 判断多边形顶点的排列方向,方法一 10 6. 判断多边形顶点的排列方向,方法二 10 7. 射线法判断点是否在多边形内 10 8. 判断点是否在凸多边形内 11 9. 寻找点集的graham算法 12 10.寻找点集凸包的卷包裹法 13 11.判断线段是否在多边形内 14 12.求简单多边形的重心 15 13.求凸多边形的重心 17 14.求肯定在给定多边形内的一个点 17 15.求从多边形外一点出发到该多边形的切线 18 16.判断多边形的核是否存在 19 ㈣ 的基本运算 1 .点是否在内 20 2 .求不共线的三点所确定的 21 ㈤ 矩形的基本运算 1.已知矩形三点坐标,求第4点坐标 22 ㈥ 常用算法的描述 22 ㈦ 补充 1.两关系: 24 2.判断是否在矩形内: 24 3.点到平面的距离: 25 4.点是否在直线同侧: 25 5.镜面反射线: 25 6.矩形包含: 26 7.两交点: 27 8.两公共面积: 28 9. 和直线关系: 29 10. 内切: 30 11. 求切点: 31 12. 线段的左右旋: 31

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值