Uva - 10674 - Tangents

本文探讨了浮点数比较时的精度问题,并通过一个具体问题实例介绍了如何使用dcmp函数来提高比较的准确性。此外,还详细解释了一个关于计算两个圆的公切线的算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:求两个圆的公切线。

题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1615

——>>发现一个精度问题:对于点与点的大小比较:

以前我这样写:(可以A一些题目)

bool operator < (const Point& e) const{
        return x < e.x || (dcmp(x - e.x) == 0 && y < e.y);
    }
可是,这样写在此题中会WA。。。

改成:

bool operator < (const Point& e) const{
        return dcmp(x - e.x) < 0 || (dcmp(x - e.x) == 0 && dcmp(y - e.y) < 0);
    }

这样就可以AC啦。。。感觉以后碰浮点数比较,都用上dcmp的较为稳妥。。。微笑

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>

using namespace std;

const double eps = 1e-10;
const double PI = acos(-1);

int dcmp(double x){
    return fabs(x) < eps ? 0 : (x > 0 ? 1 : -1);
}

struct Point{
    double x;
    double y;

    Point(double x = 0, double y = 0):x(x), y(y){}

    bool operator < (const Point& e) const{
        return dcmp(x - e.x) < 0 || (dcmp(x - e.x) == 0 && dcmp(y - e.y) < 0);
    }

    int read(){
        return scanf("%lf%lf", &x, &y);
    }
}p[3];

typedef Point Vector;

Vector operator + (Point A, Point B){
    return Vector(A.x + B.x, A.y + B.y);
}

Vector operator - (Point A, Point B){
    return Vector(A.x - B.x, A.y - B.y);
}

Vector operator * (Point A, double p){
    return Vector(A.x * p, A.y * p);
}

Vector operator / (Point A, double p){
    return Vector(A.x / p, A.y / p);
}

double Dot(Vector A, Vector B){
    return A.x * B.x + A.y * B.y;
}

double Cross(Vector A, Vector B){
    return A.x * B.y - B.x * A.y;
}

double Length(Vector A){
    return sqrt(Dot(A, A));
}

struct Circle{
    double x, y;
    double r;

    Circle(double x = 0, double y = 0, double r = 0):x(x), y(y), r(r){}

    int read(){
        return scanf("%lf%lf%lf", &x, &y, &r);
    }

    Point point(double a){
        return Point(x + r * cos(a), y + r * sin(a));
    }
};

int getTangents(Circle A, Circle B, Point *a, Point *b){
    int cnt = 0;        //存切点用
    if(dcmp(A.r - B.r) < 0){
        swap(A, B);
        swap(a, b);
    }
    double d = sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y));     //圆心距
    double rdiff = A.r - B.r;      //两圆半径差
    double rsum = A.r + B.r;       //两圆半径和
    if(dcmp(d - rdiff) < 0) return 0;        //1.内含
    double base = atan2(B.y - A.y, B.x - A.x);      //向量AB的极角
    if(dcmp(d) == 0) return -1;        //2.重合
    if(dcmp(d - rdiff) == 0){       //3.内切
        a[cnt] = b[cnt] = A.point(base);
        cnt++;
        return 1;
    }
    double ang = acos((A.r - B.r) / d);
    a[cnt] = A.point(base + ang); b[cnt] = B.point(base + ang); cnt++;      //4.相交(外切、外离的外公切线也在此求出)
    a[cnt] = A.point(base - ang); b[cnt] = B.point(base - ang); cnt++;      //两条外公切线的切点
    if(dcmp(d - rsum) == 0){        //5.外切
        a[cnt] = b[cnt] = A.point(base);
        cnt++;
    }
    else if(dcmp(d - rsum) > 0){      //6.外离
        double ang = acos((A.r + B.r) / d);
        a[cnt] = A.point(base + ang); b[cnt] = B.point(PI + base + ang); cnt++;
        a[cnt] = A.point(base - ang); b[cnt] = B.point(PI + base - ang); cnt++;
    }
    return cnt;
}

int main()
{
    Circle A, B;
    Point a[5], b[5];
    while(A.read() == 3 && B.read() == 3){
        if(!A.x && !A.y && !A.r && !B.x && !B.y && !B.r) return 0;
        int cnt = getTangents(A, B, a, b);
        printf("%d\n", cnt);
        if(cnt == -1 || cnt == 0) continue;
        vector<pair<Point, Point> > tan;
        for(int i = 0; i < cnt; i++) tan.push_back(make_pair(a[i], b[i]));
        sort(tan.begin(), tan.end());
        for(vector<pair<Point, Point> >::iterator iter = tan.begin(); iter != tan.end(); iter++)
            printf("%.5f %.5f %.5f %.5f %.5f\n", iter->first.x, iter->first.y, iter->second.x, iter->second.y, Length(iter->second - iter->first));
    }
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值