1.三角形的所有端点

2.过所有三角形的端点对所有圆做切线,得到所有切点。

3.做任意两圆的外公切线,得到所有切点。

对上述所有点求凸包,标记每个点是三角形上的点还是某个圆上的点。

求完凸包后,因为所有点都是按逆时针(或顺时针)排好序的,如果相邻两点在同一圆上,那么求这段圆弧的距离,否则求这段直线的距离。最后得到所有周长。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm> using namespace std; const double eps = 1e-;
const double PI = acos(-1.0);
const int MAXN = ; struct Point
{
double x, y;
int id; //点标号,标记是否在同一个圆上
Point() { }
Point( double x, double y ):x(x), y(y) { }
Point( double x, double y, int id ):x(x), y(y), id(id) { }
void readPoint()
{
scanf( "%lf%lf", &x, &y );
return;
}
}; struct Circle
{
Point c; //圆心坐标
double r; //半径
Circle() {}
Circle( Point c, double r ): c(c), r(r) {}
Point getPoint( double theta ) //根据极角返回圆上一点的坐标
{
return Point( c.x + cos(theta)*r, c.y + sin(theta)*r );
}
void readCircle()
{
scanf("%lf%lf%lf", &c.x, &c.y, &r );
return;
}
}; 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 );
} 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.x - B.x ) == && dcmp( A.y - B.y ) < );
} bool operator>( const Point& A, const Point& B ) //两点比较
{
return dcmp( A.x - B.x) > || ( dcmp(A.x - B.x ) == && dcmp( A.y - B.y ) > );
} bool operator==( const Point& a, const Point& b ) //两点相等
{
return dcmp( a.x - b.x ) == && dcmp( a.y - b.y ) == ;
} double Cross( Vector A, Vector B ) //向量叉积
{
return A.x * B.y - A.y * B.x;
} double PointDis( Point a, Point b ) //两点距离的平方
{
return (a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y);
} //求凸包,graham算法,O(nlogn),返回凸包点的个数
int graham( Point *p, int n, Point *ch )
{
if ( n <= ) return ;
int top = ;
sort( p, p + n ); ch[ top ] = p[];
ch[ ++top ] = p[];
ch[ ++top ] = p[]; top = ; for ( int i = ; i < n; ++i )
{
while ( top && dcmp( Cross( ch[top] - ch[top - ], p[i] - ch[top - ] ) ) <= ) --top;
ch[++top] = p[i];
}
int len = top;
ch[++top] = p[n - ];
for ( int i = n - ; i >= ; --i )
{
while ( top > len && dcmp( Cross( ch[top] - ch[top - ], p[i] - ch[top - ] ) ) <= ) --top;
ch[++top] = p[i];
}
return top;
} //过定点做圆的切线,得到切点,返回切点个数
//tps保存切点坐标
int getTangentPoints( Point p, Circle C, Point *tps )
{
int cnt = ; double dis = sqrt( PointDis( p, C.c ) );
int aa = dcmp( dis - C.r );
if ( aa < ) return ; //点在圆内
else if ( aa == ) //点在圆上,该点就是切点
{
tps[cnt] = p;
++cnt;
return cnt;
} //点在圆外,有两个切点
double base = atan2( p.y - C.c.y, p.x - C.c.x );
double ang = acos( C.r / dis );
//printf( "base = %f ang=%f\n", base, ang );
//printf( "base-ang=%f base+ang=%f \n", base - ang, base + ang ); tps[cnt] = C.getPoint( base - ang ), ++cnt;
tps[cnt] = C.getPoint( base + ang ), ++cnt; return cnt;
} //求两圆外公切线切点,返回切线个数
//p是圆c2在圆c1上的切点
int makeCircle( Circle c1, Circle c2, Point *p )
{
int cnt = ;
double d = sqrt( PointDis(c1.c, c2.c) ), dr = c1.r - c2.r;
double b = acos(dr / d);
double a = atan2( c2.c.y - c1.c.y, c2.c.x - c1.c.x );
double a1 = a - b, a2 = a + b;
p[cnt++] = Point(cos(a1) * c1.r, sin(a1) * c1.r) + c1.c;
p[cnt++] = Point(cos(a2) * c1.r, sin(a2) * c1.r) + c1.c;
return cnt;
} double DisOnCircle( Point a, Point b, Circle c ) //求圆上一段弧长
{
Point o = c.c;
double A = sqrt( PointDis( o, a ) );
double B = sqrt( PointDis( o, b ) );
double C = sqrt( PointDis( a, b ) );
double alpha = acos( ( A*A + B*B - C*C ) / ( 2.0*A*B ) );
if ( dcmp( Cross( o-a, o-b ) ) < ) return alpha * c.r;
else return ( 2.0*PI - alpha ) * c.r;
} /**********************以上模板**********************/ int cntC, cntT; //圆的个数,三角形的个数
Circle yuan[MAXN]; //所有圆
Point PP[]; //所有点
Point tubao[]; //凸包
int totPP; //点总数 void showP( Point *p, int nn )
{
printf( "allP = %d\n", nn );
for ( int i = ; i < nn; ++i )
printf("%f %f\n", p[i].x, p[i].y );
puts("-------------------------");
return;
} int main()
{
//freopen( "10022.in", "r", stdin );
//freopen( "s.out", "w", stdout );
while ( scanf( "%d%d", &cntC, &cntT ) == )
{
totPP = ;
for ( int i = ; i < cntC; ++i )
yuan[i].readCircle();
for ( int i = ; i < cntT; ++i )
{
for ( int j = ; j < ; ++j )
{
PP[totPP].readPoint();
PP[totPP].id = -(totPP+);
++totPP;
}
} if ( cntC == && cntT == )
{
printf("%.6f\n", 2.0 * PI * yuan[].r );
continue;
} int pretot = totPP;
//求两圆的外切点
for ( int i = ; i < cntC; ++i )
for ( int j = i + ; j < cntC; ++j )
{
Point PonA[], PonB[];
makeCircle( yuan[i], yuan[j], PonA );
int ans = makeCircle( yuan[j], yuan[i], PonB );
for ( int k = ; k < ans; ++k )
{
PonA[k].id = i;
PonB[k].id = j;
PP[totPP++] = PonA[k];
PP[totPP++] = PonB[k];
}
} //求所有点与所有圆的切点
for ( int i = ; i < pretot; ++i )
{
for ( int j = ; j < cntC; ++j )
{
Point qiedian[];
int ans = getTangentPoints( PP[i], yuan[j], qiedian );
for ( int k = ; k < ans; ++k )
{
qiedian[k].id = j;
PP[totPP++] = qiedian[k];
}
}
} //showP( PP, totPP );
int cntBao = graham( PP, totPP, tubao );
//puts("*********");
//showP( tubao, cntBao );
double girth = 0.0;
tubao[cntBao] = tubao[]; for ( int i = ; i <= cntBao; ++i )
{
if ( tubao[i].id == tubao[i - ].id ) //如果两点在同一个圆上
girth += DisOnCircle( tubao[i], tubao[i - ], yuan[ tubao[i].id ] );
else
girth += sqrt( PointDis( tubao[i], tubao[i - ] ) ); } printf( "%.5lf\n", girth );
}
return ;
}

HDU 4667 Building Fence 计算几何 凸包+圆的更多相关文章

  1. HDU 4667 Building Fence(求凸包的周长)

    A - Building Fence Time Limit:1000MS     Memory Limit:65535KB     64bit IO Format:%I64d & %I64u ...

  2. hdu 4667 Building Fence < 计算几何模板>

    //大白p263 #include <cmath> #include <cstdio> #include <cstring> #include <string ...

  3. HDU 4667 Building Fence(2013多校7 1002题 计算几何,凸包,圆和三角形)

    Building Fence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)To ...

  4. HDU 4667 Building Fence

    题意: 给n个圆和m个三角形,且保证互不相交,用一个篱笆把他们围起来,求最短的周长是多少. 做法:--水过... 把一个圆均匀的切割成500个点,然后求凸包. 注意:求完凸包,在求周长的时候记得要把圆 ...

  5. 4667 Building Fence 解题报告

    题意:给n个圆和m个三角形,且保证互不相交,用一个篱笆把他们围起来,求最短的周长是多少. 解法1:在每个圆上均匀的取2000个点,求凸包周长就可以水过. 解法2:求出所有圆之间的外公切线的切点,以及过 ...

  6. [hdu4667]Building Fence 计算几何 瞎瘠薄搞

    大致题意: 给出n个圆和m个三角形,求最小的的,能将所有图形覆盖的图形的周长. 正解为求所有三角形顶点与圆的切点以及圆和圆的切点构造凸包,再求路径. 因为要求结果误差<=1e-3 所以 我们可以 ...

  7. HDU 5130 Signal Interference(计算几何 + 模板)

    HDU 5130 Signal Interference(计算几何 + 模板) 题目链接http://acm.hdu.edu.cn/showproblem.php?pid=5130 Descripti ...

  8. HDU 5033 Building(单调栈)

    HDU 5033 Building(单调栈) 题目链接http://acm.hdu.edu.cn/showproblem.php?pid=5033 Description Once upon a ti ...

  9. HDU—— 5159 Building Blocks

    Problem Description After enjoying the movie,LeLe went home alone. LeLe decided to build blocks. LeL ...

随机推荐

  1. Spring使用Setter依赖注入

    一个简单的Spring例子来展示如何通过setter方法注入依赖项,最常用DI方法注入bean. 1. IOutputGenerator 接口和实现类   package faj.test.javad ...

  2. 如何在spring中运行多个schedulers quartz 实例

    http://wzping.iteye.com/blog/468263 1.定义一个JOB <!-- 使用pojo来做job,指定pojo和method -->     <bean ...

  3. ajax实现分页页签

    在一些搜索列表的页面中,我们会遇到一些需要处理页签的需求,一般这样的页面,要么是在JSP中处理,每次都跳页.这样做是个很方便的方法.但是如果页面上有很多和列表无关,每次都需要重新渲染是不是显得慢了一些 ...

  4. 【javascript】ajax 基础

    什么是 ajax ajax 即“Asynchronous JavaScript and XML”(异步 JavaScript 和 XML),也就是无刷新数据读取. http 请求 首先需要了解 htt ...

  5. ajax实现无刷新两级联动DropDownList

    ajax实现的无刷新三级联动 http://zhangyu028.cnblogs.com/articles/310568.html 本文来自小山blog:http://singlepine.cnblo ...

  6. django中介模型,CBV模型,及logging日志配制

    1.中介模型 中介模型,这个是在我们创建表格时,多对多添加的时候应用到的,通过制定ManyToManyField字段中的through参数来定义,为两者的关系新建一个中介class 为什么会产生这个中 ...

  7. dicom和dicomdir

    转载http://blog.sina.com.cn/s/blog_4bce5f4b01019ix5.html DICOM 文件内容在 Part 3 DICOM IOD 里定义.CT, MR, CR, ...

  8. MappingException:class com.zsn.crm.Model.user not found whie looking for property user id

    之前好好地运行 什么东西都没动过 再次运行突然报异常*****MappingException:class com.zsn.crm.Model.user not found whie looking ...

  9. JQuery实现子级选择器

    效果图如下: HTML代码如下: <!DOCTYPE html> <html lang="en"> <head> <meta charse ...

  10. asp.net高并发网站解决方案【未完成版本】

    场景:假设现在是一个电商网站,今天要举办活动,有10个商品低价销售,但是会来抢购的人会特别多,最后只有十个人可以成功的买到商品   明确2个问题 1.访问量:抢票时间断用户访问量 2.并发:1秒内请求 ...