题目:http://acm.hdu.edu.cn/showproblem.php?pid=4667
题目大意:给你n个圆,m个三角形,两两不重叠,问你把他们全都围起来的最短的篱笆的长度。
思路:我的做法是暴力,三角形不用处理,因为就三个点,圆的话,直接枚举角度,把它拆成点,然后上凸包,飘时限和精度。。。
经过不懈的努力之后,终于用G++ 900ms+ 飘过了,补充一句,C++TLE。。 = =
比赛的时候剩下一个半小时搞这道,因为搞计算几何的队友不在,木有搞过计算几何,也木有模板,明确暴力的思路后,就去网上乱找模板,结果找 cuo 了,最后还是没A。。 T^T
暴力代码如下:
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const double eps = 1e-8; const double PI = acos(-1.0); const int MAXN = 11111111 ; struct Point { double x, y; Point(){} Point(double a,double b): x(a),y(b) {} Point operator - (const Point& t) const { Point tmp; tmp.x = x - t.x; tmp.y = y - t.y; return tmp; } Point operator + (const Point& t) const { Point tmp; tmp.x = x + t.x; tmp.y = y + t.y; return tmp; } bool operator == (const Point& t) const { return fabs(x-t.x) < eps && fabs(y-t.y) < eps; } }GP,point[MAXN]; struct Cir { Point ct; double r; }; inline double Cross(Point a, Point b, Point c) { // 叉积 return (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y); } inline double PPdis(Point a, Point b) { // 点点距离 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } inline double PLdis(Point p,Point l1,Point l2){ // 点线距离 return fabs(Cross(p,l1,l2))/PPdis(l1,l2); } inline bool same_dir(Point a, Point b) { // 向量是否同向 return fabs(a.x*b.y-b.x*a.y) < eps && a.x*b.x > -eps && a.y*b.y > -eps; } bool dotOnSeg(Point p, Point s, Point e) { // 点是否在线段上 if ( p == s || p == e ) // 看具体情况端点是否合法 return true; return fabs((p-s).x*(p-e).y - (p-e).y*(p-s).x) < eps && (p.x-s.x)*(p.x-e.x)<eps && (p.y-s.y)*(p.y-e.y)<eps; } bool Intersect(Point p1, Point p2, Point p3, Point p4, Point& p) { // 直线相交 double a1, b1, c1, a2, b2, c2, d; a1 = p1.y - p2.y; b1 = p2.x - p1.x; c1 = p1.x*p2.y - p2.x*p1.y; a2 = p3.y - p4.y; b2 = p4.x - p3.x; c2 = p3.x*p4.y - p4.x*p3.y; d = a1*b2 - a2*b1; if ( fabs(d) < eps ) return false; p.x = (-c1*b2 + c2*b1) / d; p.y = (-a1*c2 + a2*c1) / d; return true; } bool cmpyx(Point a, Point b) { if ( a.y != b.y ) return a.y < b.y; return a.x < b.x; } void Grahamxy(Point *p, int &n) { // 水平序(住:两倍空间) if ( n < 3 ) return; int i, m=0, top=1; sort(p, p+n, cmpyx); for (i=n; i < 2*n-1; i++) p[i] = p[2*n-2-i]; for (i=2; i < 2*n-1; i++) { while ( top > m && Cross(p[top], p[i], p[top-1]) < eps ) top--; p[++top] = p[i]; if ( i == n-1 ) m = top; } n = top; } bool cmpag(Point a, Point b) { double t = (a-GP).x*(b-GP).y - (b-GP).x*(a-GP).y; return fabs(t) > eps ? t > 0 : PPdis(a, GP) < PPdis(b, GP); } void Grahamag(Point *p, int &n) { // 极角序 int i, top = 1; GP = p[0]; for (i=1; i < n; i++) if(p[i].y<GP.y-eps || (fabs(p[i].y-GP.y)<eps && p[i].x<GP.x)) { GP = p[i]; } sort(p, p+n, cmpag); for ( i=2; i < n; i++ ) { while ( top > 0 && Cross(p[top], p[i], p[top-1]) < eps ) top--; p[++top] = p[i]; } p[++top] = p[0]; n = top; } int main() { int n,m; while(~scanf("%d%d",&n,&m)) { int tot = 0; double x,y,r; for(int i = 0;i<n;i++) { scanf("%lf%lf%lf",&x,&y,&r); for(double j = 0;j<2*PI;j += 0.0032) { point[tot++] = Point(x+r*cos(j),y+r*sin(j)); } } for(int i = 0;i<m;i++) for(int j = 0;j<3;j++) { scanf("%lf%lf",&x,&y); point[tot++] = Point(x,y); } Grahamxy(point,tot); /* printf("tot = %d\n",tot); for(int i = 0;i<tot;i++) printf("i = %d,x = %lf,y = %lf\n",i,point[i].x,point[i].y); */ double ans = 0; Point pre = point[0]; for(int i = 1;i<tot;i++) { ans += PPdis(point[i],pre); pre = point[i]; } ans += PPdis(point[0],pre); printf("%.5f\n",ans); } return 0; }