题意:

给出两个圆的圆心坐标和半径,求这两个圆的公切线切点的坐标及对应线段长度。若两圆重合,有无数条公切线则输出-1.

输出是按照一定顺序输出的。

分析:

首先情况比较多,要一一判断,不要漏掉。

如果高中的那点老底还在的话,代码还是很好理解的。

 //#define LOCAL
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std; const double PI = acos(-1.0);
const double EPS = 1e-;
struct Point
{
double x, y;
Point(double x=, double y=):x(x), y(y) {} };
typedef Point Vector;
Vector operator + (Vector A, Vector B)
{
return Vector(A.x+B.x, A.y+B.y);
}
Vector operator - (Vector A, Vector B)
{
return Vector(A.x-B.x, A.y-B.y);
}
Vector operator * (Vector A, double p)
{
return Vector(A.x*p, A.y*p);
}
Vector operator / (Vector A, double p)
{
return Vector(A.x/p, A.y/p);
}
double dcmp(double x)
{
if(fabs(x) < EPS) return ;
else return x < ? - : ;
}
bool operator < (const Vector& a, const Vector& b)
{
return dcmp(a.x-b.x) < || dcmp(a.x-b.x) == && dcmp(a.y-b.y) < ;
}
bool operator == (const Vector& a, const Vector& b)
{
return dcmp(a.x-b.x) == && dcmp(a.y-b.y) == ;
}
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 - a.y*b.x;
}
double Length(Vector a)
{
return sqrt(Dot(a, a));
}
struct Circle
{
double x, y, r;
Circle(double x, double y, double r):x(x), y(y), r(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 = ;
if(A.r < B.r) { swap(A, B); swap(a, b); }
double d2 = (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(d2 < rdiff*rdiff) return ; //内含 double base = atan2(B.y-A.y, B.x-A.x);
if(dcmp(d2) == && dcmp(A.r - B.r) == ) return -; //重合
if(dcmp(d2 - rdiff*rdiff) == ) //内切
{
a[cnt] = A.point(base); b[cnt] = B.point(base); cnt++;
return ;
} //有外公切线
double ang = acos((A.r - B.r) / sqrt(d2));
a[cnt] = A.point(base + ang); b[cnt] = B.point(base + ang); cnt++;
a[cnt] = A.point(base - ang); b[cnt] = B.point(base - ang); cnt++;
if(dcmp(rsum*rsum - d2) == )
{//外切
a[cnt] = b[cnt] = A.point(base); cnt++;
}
else if(dcmp(d2 - rsum*rsum) > )
{
ang = acos((A.r + B.r) / sqrt(d2));
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(void)
{
#ifdef LOCAL
freopen("10674in.txt", "r", stdin);
#endif int x1, y1, r1, x2, y2, r2;
while(scanf("%d%d%d%d%d%d", &x1, &y1, &r1, &x2, &y2, &r2) == && r1 && r2)
{
Point a[], b[];
Circle C1(x1, y1, r1), C2(x2, y2, r2);
int n = getTangents(C1, C2, a, b);
printf("%d\n", n);
int p[] = {, , , };
for(int i = ; i < n; ++i)
for(int j = i+; j < n; ++j)
if(a[p[j]] < a[p[i]] || (a[p[j]] == a[p[i]] && b[p[j]] < b[p[i]])) swap(p[i], p[j]);
for(int i = ; i < n; ++i)
printf("%.5lf %.5lf %.5lf %.5lf %.5lf\n", a[p[i]].x, a[p[i]].y, b[p[i]].x, b[p[i]].y, Length(a[p[i]] - b[p[i]]));
} return ;
}

代码君

写的第一份,样例过,自己随机生成的1000组数据和lrj的代码对比,输出也是一模一样的,可就是无线WA。

这里还是贴一下这份“神奇”的代码吧,也许日后能发现这个隐藏的错误。

 //#define LOCAL
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std; struct Point
{
double x, y;
Point(double x=, double y=) :x(x),y(y) {}
};
typedef Point Vector;
const double EPS = 1e-;
Vector operator + (Vector A, Vector B) { return Vector(A.x + B.x, A.y + B.y); }
Vector operator - (Vector A, Vector B) { return Vector(A.x - B.x, A.y - B.y); }
Vector operator * (Vector A, double p) { return Vector(A.x*p, A.y*p); }
Vector operator / (Vector A, double p) { return Vector(A.x/p, A.y/p); }
bool operator < (const Point& a, const Point& b)
{ return a.x < b.x || (a.x == b.x && a.y < b.y); }
int dcmp(double x)
{ if(fabs(x) < EPS) return ; else return x < ? - : ; }
bool operator == (const Point& a, const Point& b)
{ return dcmp(a.x-b.x) == && dcmp(a.y-b.y) == ; }
double Dot(Vector A, Vector B)
{ return A.x*B.x + A.y*B.y; }
double Length(Vector A) { return sqrt(Dot(A, A)); } struct Circle
{
Point c; //Ô²ÐÄ
double r; //°ë¾¶
//Circle(Point c, double r):c(c), r(r) {}
Point point(double a)
{//Çó¶ÔÓ¦Ô²ÐĽǵĵã
return Point(c.x + r*cos(a), c.y + r*sin(a));
}
};
double angle(Vector v) { return atan2(v.y, v.x); }
const double PI = acos(-1.0); int getTangents(Circle A, Circle B, Point* a, Point* b)
{
int cnt = ;
if(A.r < B.r) { swap(A, B); swap(a, b); }
double d2 = (A.c.x-B.c.x)*(A.c.x-B.c.x) + (A.c.y-B.c.y)*(A.c.y-B.c.y);
double rdiff = A.r - B.r;
double rsum = A.r + B.r;
if(d2 < rdiff*rdiff) return ; //ÄÚº¬ double base = atan2(B.c.y-A.c.y, B.c.x-A.c.x);
if(dcmp(d2) == && dcmp(A.r-B.r) == ) return -; //Á½Ô²Öغϣ¬ÎÞÇî¶àÌõÇÐÏß
if(dcmp(d2 - rdiff*rdiff) == ) //ÄÚÇÐ
{
a[cnt] = A.point(base);
b[cnt] = B.point(base);
cnt++;
return ;
}
//ÓÐÍ⹫ÇÐÏß
double ang = acos((A.r-B.r) / sqrt(d2));
a[cnt] = A.point(base+ang); b[cnt] = B.point(base+ang); cnt++;
a[cnt] = A.point(base-ang); b[cnt] = B.point(base-ang); cnt++; if(dcmp(d2 - rsum*rsum) == ) //Ò»ÌõÄÚ¹«ÇÐÏß
{
a[cnt] = b[cnt] = A.point(base); cnt++;
}
else if(dcmp(d2 - rsum*rsum) > )
{
double ang = acos((A.r+B.r) / sqrt(d2));
a[cnt] = A.point(base+ang); b[cnt] = B.point(base+ang+PI); cnt++;
a[cnt] = A.point(base-ang); b[cnt] = B.point(base-ang+PI); cnt++;
}
//for(int i = 0; i < cnt; ++i)
// printf("%.5lf %.5lf %.5lf %.5lf\n", a[i].x, a[i].y, b[i].x, b[i].y);
return cnt;
} int main(void)
{
#ifdef LOCAL
freopen("10674in.txt", "r", stdin);
//freopen("10674out.txt", "w", stdout);
#endif int x1, y1, r1, x2, y2, r2;
while(scanf("%d%d%d%d%d%d", &x1, &y1, &r1, &x2, &y2, &r2) == && dcmp(r1) > )
{
Point a[], b[];
/*Point p1(x1, y1), p2(x2, y2);
Circle C1(p1, r1), C2(p2, r2);*/
Circle C1, C2;
C1.c.x=x1, C1.c.y=y1, C1.r=r1;
C2.c.x=x2, C2.c.y=y2, C2.r=r2;
int n = getTangents(C1, C2, a, b);
printf("%d\n", n);
if(n > )
{
int p[] = {, , , };
for(int i = ; i < n; ++i)
for(int j = i+; j < n; ++j)
if(a[p[j]] < a[p[i]] || (a[p[j]] == a[p[i]] && b[p[j]] < b[p[i]])) swap(p[i], p[j]);
for(int i = ; i < n; ++i)
printf("%.5lf %.5lf %.5lf %.5lf %.5lf\n", a[p[i]].x, a[p[i]].y, b[p[i]].x, b[p[i]].y, Length(a[p[i]] - b[p[i]]));
}
} return ;
}

WA掉的代码君

UVa 10674 (求两圆公切线) Tangents的更多相关文章

  1. POJ 2546 &amp; ZOJ 1597 Circular Area(求两圆相交的面积 模板)

    题目链接: POJ:http://poj.org/problem? id=2546 ZOJ:problemId=597" target="_blank">http: ...

  2. 求两圆相交部分面积(C++)

    已知两圆圆心坐标和半径,求相交部分面积: #include <iostream> using namespace std; #include<cmath> #include&l ...

  3. hdu5858 Hard problem(求两圆相交面积)

    题目传送门 Hard problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Other ...

  4. hdu 5120 (求两圆相交的面积

    题意:告诉你两个圆环,求圆环相交的面积. /* gyt Live up to every day */ #include<cstdio> #include<cmath> #in ...

  5. Gym-101915B Ali and Wi-Fi 计算几何 求两圆交点

    题面 题意:给你n个圆,每个圆有一个权值,你可以选择一个点,可以获得覆盖这个点的圆中,权值最大的m个的权值,问最多权值是多少 题解:好像是叙利亚的题....我们画画图就知道,我们要找的就是圆与圆交的那 ...

  6. 2D空间中求两圆的交点

    出处:https://stackoverflow.com/questions/19916880/sphere-sphere-intersection-c-3d-coordinates-of-colli ...

  7. java求两个圆相交坐标

    最近由于项目需要,根据两个圆函数求出相交的坐标.实现代码如下,另感谢两圆求交点算法实现Java代码,虽然他所贡献的代码中存在问题,但仍有借鉴意义. 1.两个圆相交的数学求法 在中学数学中我们知道,一个 ...

  8. ●UVA 10674 Tangents

    题链: https://vjudge.net/problem/UVA-10674 题解: 计算几何,求两个圆的公切线. <算法竞赛入门经典——训练指南>P266,讲得很清楚的. 大致是分为 ...

  9. GPS(2)关于位置的3个示例,实时获取GPS定位数据,求两个经纬点距离,邻近某个区域圆时警告

    实时获取GPS定位数据 import android.app.Activity; import android.content.Context; import android.location.Loc ...

随机推荐

  1. iOS上用FTGL显示定制Truetype字体碰到的问题

    没想到这个问题搞了快2个月时间:当然跟我只是断断续续地工作有关. FTGL是freetype的opengl实现.我接触FTGL最初只是为了练习OpenGL,写几个简单的游戏app.开始试了试FTGL觉 ...

  2. Codeforces Round #358 (Div. 2) D. Alyona and Strings 字符串dp

    题目链接: 题目 D. Alyona and Strings time limit per test2 seconds memory limit per test256 megabytes input ...

  3. IntelliJ IDEA 比较当前版本文件与历史文件

    前言: 写代码修改后怎样比较与历史文件的区别呢?idea提供了2种比较方式(目前笔者所了解到的) 一.SVN的版本比较 二.当前文件与历史版本比较

  4. Linux命令zip和unzip

    问题描述:        使用Linux中命令zip和unzip 问题解决: 命令名: zip  功能说明:压缩文件. 语 法:zip [-AcdDfFghjJKlLmoqrSTuvVwXyz$][- ...

  5. SQL Server 之 事务隔离级别

    SET TRANSACTION ISOLATION LEVEL xxx  -- 每次设置只针对当前事务块 xxx 取值: READ UNCOMMITTED READ COMMITTED REPEATA ...

  6. Codeforces Round #241 (Div. 2)->A. Guess a number!

    A. Guess a number! time limit per test 1 second memory limit per test 256 megabytes input standard i ...

  7. 【锋利的JQuery-学习笔记】添加提示图片

    效果图: hot图片: (注意:这个图标本身就有抖动效果的,并不是由于标签<del>而具有抖动效果) 周期性抖动,起到提示的作用 html: <div class="jnC ...

  8. (一)、http原理

    谣言粉碎机前些日子发布的<用公共WiFi上网会危害银行账户安全吗?>,文中介绍了在使用HTTPS进行网络加密传输的一些情况,从回复来看,争议还是有的.随着网络越来越普及,应用越来越广泛,一 ...

  9. js注册验证【转】

    function getFocus() //设置用户名文本框获取焦点 { document.getElementById("txtuname").focus(); } functi ...

  10. Mysql 1030 Got error -1 from storage engine 错误解决

    检查你的my.cnf或my.ini,里面会有一个参数innodb_force_recovery,你看看他的值,默认是没有这个参数,没有的话,他的默认值是0,这个参数的值如果大于0,innodb会被禁止 ...