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. machine learning trends from nips14

    from John Platt, Deputy Managing Director and Distinguished Scientist at Microsoft Research http://b ...

  2. Android学习<2>

    Android自学资料汇总 资料参考地址: http://blog.csdn.net/guolin_blog/article/details/26365913 http://drakeet.me/an ...

  3. ECMAscript6(ES6)新特性语法总结(一)

    ES6/ES2015,,在ES5的基础上扩展了很多新的功能,在使用的时候要慎重,因为有一部分js代码在部分浏览器是不兼容的,但是所有写在服务器端的代码基本上都支持ES6的写法. 新特性: 一.开启严格 ...

  4. phpmailer类的再封装

    email <?php use PHPMailer\PHPMailer\PHPMailer; class Email { const SMTPDebug = 2; const HOST = 's ...

  5. Nginx 配置继承模型

    要了解nginx的继承模型,首先需要知道nginx使用多个配置块进行操作.在nginx中,这样的块被称为上下文,例如,放置在服务器上下文中的配置指令驻留在server { }块中,就像放置在http上 ...

  6. 10.2 DOM 操作技术【JavaScript高级程序设计第三版】

    很多时候,DOM 操作都比较简明,因此用JavaScript 生成那些通常原本是用HTML 代码生成的内容并不麻烦.不过,也有一些时候,操作DOM 并不像表面上看起来那么简单.由于浏览器中充斥着隐藏的 ...

  7. iptables v1.3.5: multiple -d flags not allowed错误已解决

    今天写了一条iptables的规则 iptables -t filter -A INPUT -s 192.168.192.0/24 -d 192.168.192.140 -p tcp -dport 2 ...

  8. POJ:3320-Jessica's Reading Problem(尺取法)

    Jessica's Reading Problem Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 15224 Accepted: ...

  9. WPF的线程模型

    原文:WPF的线程模型 WPF的线程模型            周银辉 谈到多线程,很多人对其可能都不太有好感,觉得麻烦与易出错.所以我们不排除有这样的情况:假设我对“多线程”.“异步”这些字眼潜意识 ...

  10. css媒体类型

    all 用于所有的媒体设备. aural 用于语音和音频合成器. braille 用于盲人用点字法触觉回馈设备. embossed 用于分页的盲人用点字法打印机. handheld 用于小的手持的设备 ...