(beginer)圆和圆相交 UVA 10969 - Sweet Dream

来源:互联网 发布:生产工艺流程图软件 编辑:程序博客网 时间:2024/06/06 01:13

Problem F

Sweet Dream

Are you ready to have a sweet dream? OK! Close your eyes (Hey! Do NOT! I was kidding! How can you read the problem statement with your eyes closed? Umm! Let me think . . . Yes! There is a good solution to this problem. Simply, hand this paper to your teammate and let him read it aloud for you)!

. . . You are standing in the middle of a room and you have a handful of discs of different sizes. They are heavy. You somehow feel uncomfortable. Calm down and don’t worry! I am going to help you feel comfortable again. Simply choose one of the discs in your hand randomly and drop it on the floor. Yes! You feel a little more comfortable. Choose and drop another! Then another one! . . . And continue this process until your hands are empty. Now, you are as light as a feather and you are ready to fly away . . .

 

But don’t be so quick! Before flying away, you should solve a problem. Open your eyes and take a look at the floor. You see the discs you’ve just dropped (To the teammate reading this problem aloud: Show the contents of figure 1 to your teammate who is going to open his eyes now).

 

 

Figure 1. Discs on the floor viewed from the above

 

 

You can see that some discs are partially (or totally) covered by other discs. Your job is to compute the total perimeter of parts of the discs that you can see from the above.

 

Umm! I think you feel a little bit uncomfortable again. Am I right?

 

The Input

The first line of input contains a single integer  which is the number of test cases. Each test case starts with a single integer , the number of discs originally in your hand followed by  lines, the th of which containing three floating-point numbers which are , radius of the th disc and  the coordinates of the point on the floor on which the disc has fallen. Two floating-point numbers are assumed to be equal if their absolute difference is less than .

 

 

The Output

Output for each test case consists of a line containing a floating-point number which is the total perimeter of part of discs that can be seen from above rounded to 3 decimal digits after the fraction point. The number should have exactly 3 digits after the fraction point.

 

 

 

Sample Input

3

1

10 0 0

2

5 0 0

10 0 0

2

1 0 0

1 1 0

 

Sample Output

62.832

62.832

10.472

 


Amirkabir University of Technology - Local Contest - Round #2 


题意:在平面上依次放置n个圆盘,后放的会覆盖之前放的,问最后能看到多长的弧长。


思路:我们对每个圆求出他与上层的圆的交点,然后得出了一段段的圆弧,然后我们判断每段圆弧是否被覆盖,未覆盖就算上,覆盖了就不算,是否覆盖可以取圆弧上任意一点看是否在上层的圆盘中。


代码:

#include<iostream>#include<cstdio>#include<string.h>#include<math.h>#include<cstring>#include<algorithm>#include<vector>using namespace std;#define eps 1e-10const double PI = 4*atan(1.0);struct Point{Point (double xx=0,double yy=0) : x(xx) , y(yy) { }double x;double y;};typedef Point Vector;Vector operator+(Vector  v1,Vector  v2) { return Vector(v1.x+v2.x,v1.y+v2.y); }Vector operator-(Vector  v1,Vector  v2) { return Vector(v1.x-v2.x,v1.y-v2.y); }Vector operator*(Vector  v, double p) { return Vector(v.x*p,v.y*p); }Vector operator/(Vector  v,double p) { return Vector(v.x/p,v.y/p); }bool operator < (Point  a,Point  b) { return a.x < b.x || (a.x==b.x && a.y > b.y); }int dcmp(double x) {if (fabs(x) < eps) return 0;return x < 0 ? -1 : 1; }bool operator==(const Point & a,const Point & b) {return dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0;}inline double toRad(double x) { return x * PI/180; }inline double toDegreed(double rad) { return rad*180/PI; }double Dot(Vector  A,Vector  B) { return A.x*B.x+A.y*B.y; }double Length(Vector  A) { return sqrt(Dot(A,A)); }double Angle(Vector A,Vector B) { return acos(Dot(A,B)/Length(A)/Length(B)); }double Cross(Vector A,Vector B) { return A.x*B.y-A.y*B.x; }double Area2(Point a,Point b,Point c) {  return Cross(b-a,c-a); }Vector Rotate(Vector A,double rad) {return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));}Vector Normal(Vector A) { double L = Length(A); return Vector(-A.y/L,A.x/L); }//点和直线Point GetLineIntersection(Point P,Vector v,Point Q,Vector w){Vector u = P-Q;double t = Cross(w,u) / Cross(v,w);return P+v*t;}double DistanceToLine(Point P,Point A,Point B) {Vector v1 = B-A , v2 = P-A;return fabs(Cross(v1,v2))/Length(v1);}double DistanceToSegment(Point P,Point A,Point B){if (A==B) return Length(P-A);Vector v1 = B-A , v2 = P-A , v3 = P-B;if (dcmp(Dot(v1,v2)) < 0) return Length(v2);else if (dcmp(Dot(v1,v3)) > 0) return Length(v3);else return fabs(Cross(v1,v2))/Length(v1);}Point GetLineProjection(Point P,Point A,Point B) {Vector v = B-A;return A+v*(Dot(v,P-A)/Dot(v,v));}bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2) {double c1 = Cross(a2-a1,b1-a1) , c2 = Cross(a2-a1,b2-a1) ,     c3 = Cross(b2-b1,a1-b1) , c4 = Cross(b2-b1,a2-b1);return dcmp(c1)*dcmp(c2) < 0 && dcmp(c3)*dcmp(c4)<0;}bool OnSegment(Point p,Point a,Point b) {return dcmp(Cross(a-p,b-p))==0 && dcmp(Dot(a-p,b-p)) < 0;}//--------------------------------------------------------------------------------------------//直线和直线struct Line{Point P;//直线上任意一点Vector v;// 方向向量。它的左边就是对应的半平面double ang;//极角Line() { }Line(Point P,Vector v) : P(P) , v(v) { ang = atan2(v.y,v.x); }bool operator < (const Line& L) const { return ang < L. ang; } //排序用的比较运算符Point point(double x) { return v*(x-P.x)+P; }};//点p在有向直线L的左边(线上不算)bool OnLeft(Line L , Point p) { return Cross(L.v,p-L.P) > 0; }//二直线交点。假定交点唯一存在Point GetIntersection(Line a,Line b) {Vector u = a.P-b.P;double t = Cross(b.v,u) / Cross(a.v,b.v);return a.P+a.v*t;}//半平面交的过程int HalfplaneIntersection(Line* L,int n,Point* poly){sort(L,L+n);     //按极角排序int first , last;//双端队列的第一个元素和最后一个元素的下表Point *p = new Point[n];//p[i]为q[i]和q[i+1]的交点Line *q = new Line[n];//双端队列q[first=last=0] = L[0];//双端队列初始化为只有一个半平面L[0]for (int i = 1 ; i < n ; ++i) {while (first < last && !OnLeft(L[i],p[last-1])) --last;while (first < last && !OnLeft(L[i],p[first])) ++first;q[++last] = L[i];if (fabs(Cross(q[last].v,q[last-1].v)) < eps) {--last;if (OnLeft(q[last],L[i].P)) q[last] = L[i];}if (first < last) p[last-1] = GetIntersection(q[last-1],q[last]);}while (first < last && !OnLeft(q[first],p[last-1])) --last;//删除无用平面(*)if (last - first <=1 ) return 0;                    //空集(**)p[last] = GetIntersection(q[last],q[first]);//计算首尾两个半平面的交点//从deque复制到输出中int m = 0;for (int i = first ; i <= last ; ++i) poly[m++] = p[i];return m ;}//--------------------------------------------//与圆相关struct Circle {Circle() { }Point c;double r;Circle(Point c, double r) : c(c) , r(r) { }Point point (double a) { return Point(c.x+cos(a)*r,c.y+sin(a)*r); }};int getLineCircleIntersection(Line L,Circle C,double &t1,double &t2,vector<Point>& sol){double a = L.v.x , b = L.P.x-C.c.x , c= L.v.y, d = L.P.y-C.c.y;double e = a*a+c*c , f = 2*(a*b+c*d) , g = b*b+d*d-C.r*C.r;double delta = f*f-4*e*g;//判别式if (dcmp(delta) < 0) return 0;//相离if (dcmp(delta)==0) {                   //相切t1 = t2 = -f/(2*e); sol.push_back(L.point(t1));return 1;}//相交t1 = (-f-sqrt(delta)) / (2*e); sol.push_back(L.point(t1));t2 = (-f+sqrt(delta))/(2*e); sol.push_back(L.point(t2));return 2;}double angle(Vector v) { return atan2(v.y,v.x); }int getCircleCircleIntersection(Circle C1,Circle C2,vector<Point>& sol){double d = Length(C1.c-C2.c);if (dcmp(d)==0) {if (dcmp(C1.r-C2.r)==0) return -1;//两圆重合return 0;}if (dcmp(C1.r+C2.r-d) < 0) return 0;if (dcmp(fabs(C1.r-C2.r)-d) > 0) return 0;double a = angle(C2.c-C1.c);double da = acos((C1.r*C1.r+d*d-C2.r*C2.r)/(2*C1.r*d));//向量C1C2的极角//C1C2到C1P1的角Point p1 = C1.point(a-da) , p2 = C1.point(a+da);sol.push_back(p1);if (p1==p2) return 1;sol.push_back(p2);return 2;}//国电p到圆C的切线。v[i]是第i条切线的向量。返回切线条数int getTangents(Point p,Circle C,Vector* v){Vector u= C.c-p;double dist = Length(u);if (dist < C.r) return 0;else if (dcmp(dist-C.r)==0) {v[0] = Rotate(u,PI/2);return 1;} else {double ang = asin(C.r/dist);v[0] = Rotate(u,-ang);v[1] = Rotate(u,+ang);return 2;}}int getTangents(Circle A,Circle B,Point* a, Point* b){int cnt = 0;if (A.r < B.r) { swap(A,B); swap(a,b); }double d2 = Dot(A.c-B.c,A.c-B.c);double rdiff = A.r-B.r;double rsum = A.r+B.r;if (dcmp(d2-rdiff*rdiff) < 0) return 0;//内含double base = atan2(B.c.y-A.c.y,B.c.x-A.c.x);if (d2==0 && dcmp(A.r-B.r)==0) return -1;//无限多条切线if (dcmp(d2-rdiff*rdiff)==0) {                       //内切,1条切线a[cnt] = A.point(base);b[cnt] = B.point(base);++cnt;return 1;}//有外切共线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)==0) {                  //一条内公切线a[cnt] = A.point(base);b[cnt] = B.point(PI+base);++cnt;} else if (dcmp(d2-rsum*rsum)>0) {           //两条公切线double 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;}bool InCircle(Circle A,Circle B){if (dcmp(A.r-B.r)>0) return false;double d2 = Dot(A.c-B.c,A.c-B.c);double rdiff = A.r-B.r;double rsum = A.r+B.r;if (dcmp(d2-rdiff*rdiff) <= 0) return true;//内含或内切或重合return false;}//----------------------------------------------------------------------------const int maxn = 110;int n;Circle circle[maxn];bool covered(Point p,int c) {for (int i = n-1 ; i > c ; --i) {if (dcmp(Length(p-circle[i].c)-circle[i].r)<=0)return true;}return false;}void input(){for (int i = 0 ; i < n ; ++i) {Circle & c = circle[i];scanf("%lf%lf%lf",&c.r,&c.c.x,&c.c.y);}}void solve(){double ans = 0;for (int i = 0 ; i < n ; ++i) {vector<Point> inter;for (int j = i+1 ; j < n ; ++j) getCircleCircleIntersection(circle[i],circle[j],inter);vector<double> rad;for (int j = 0 ; j < inter.size() ; ++j) rad.push_back(angle(inter[j]-circle[i].c)+PI);sort(rad.begin(),rad.end());if (rad.empty() || dcmp(rad[0])!=0) rad.insert(rad.begin(),0);if (rad.empty() || dcmp(rad[rad.size()-1]-2*PI)!=0) rad.insert(rad.end(),2*PI);double S = 0;for (int j = 0; j < rad.size()-1; ++j) {Point mid = circle[i].point((rad[j]-PI+rad[j+1]-PI)*0.5);if (covered(mid,i)) continue;S += rad[j+1]-rad[j];}ans += S*circle[i].r;}printf("%.3lf\n",ans);}int main(){int T; cin>>T;while (T--) {scanf("%d",&n);input();solve();}}


0 0
原创粉丝点击