好久没做zoj了,一做就是WA一版啊啊啊啊啊!!!
这个题,给你N个圆,求相交后把平面分成了多少份。
我开始找规律的,找不太对,后来一搜,发现是欧拉定理,真无语了。刚学完离散,没想到真能用得上。
不过这个找边数和面数很纠结啊。
根据欧拉定理,连通平面图(圆相交的图一定是平面图)满足 V - E + R = 2。 其中V是顶点数,E是边数,R是面数。这题就是求面数,但是这个不一定是连通的平面图。
所以需要转换下。可以证得,如果一个图中有X个连通的平面图,那么满足,V - E + R = X+1。(某张离散卷子考试题T T ,只需要将每个连通分支按题意累和,再考虑最后重叠的最外面即可)
所以就转换成求这个图的边数和顶点数。
没想到好方法,最水的方法,就是两两相交求交点(包括切点),因为可能这些点会有重复的,比如三个圆的交点重合了三个等等,所以需要排除重合的点,我直接用快排然后筛掉想同的点。然后判断这些点(每个点都不同)在多少个圆上。画图可知,一个圆上有N个点,那么这个圆被分割成N条边,所以只要判断这些点在多少个圆上即可。
P.S.:因为这题,学了好几个圆的函数,收获还是不小滴,就是这代码有点长了。。。
#include <queue> #include <stack> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <iostream> #include <limits.h> #include <string.h> #include <string> #include <algorithm> using namespace std; const int MAX = 51; struct point{ double x,y;}; struct circle{ point a;double r;}; circle c[MAX]; point p[MAX*MAX]; const double eps = 1e-8; bool dy(double x,double y) { return x > y + eps;} // x > y bool xy(double x,double y) { return x < y - eps;} // x < y bool dyd(double x,double y) { return x > y - eps;} // x >= y bool xyd(double x,double y) { return x < y + eps;} // x <= y bool dd(double x,double y) { return fabs( x - y ) < eps;} // x == y double disp2p(point a,point b) { return sqrt( ( a.x - b.x ) * ( a.x - b.x ) + ( a.y - b.y ) * ( a.y - b.y ) ); } bool c2c_inst(circle a,circle b) { if( xy(disp2p(a.a,b.a),a.r+b.r) && dy(disp2p(a.a,b.a),fabs(a.r - b.r)) ) return true; return false; } point c2c_tangent_p(circle a,circle b) { point t; if( dd(disp2p(a.a,b.a),a.r+b.r) ) { t.x = (a.r*b.a.x + b.r*a.a.x)/(a.r + b.r); t.y = (a.r*b.a.y + b.r*a.a.y)/(a.r + b.r); return t; } t.x = (a.r*b.a.x - b.r*a.a.x)/(a.r - b.r); t.y = (a.r*b.a.y - b.r*a.a.y)/(a.r - b.r); return t; } bool c2c_tangent(circle a,circle b) { if( dd(disp2p(a.a,b.a),a.r+b.r) || dd(disp2p(a.a,b.a),fabs(a.r-b.r)) ) return true; return false; } bool cmp(point a,point b) { if( dd(a.x,b.x) ) return xy(a.y,b.y); return xy(a.x,b.x); } point l2l_inst_p(point u1,point u2,point v1,point v2) { point ans = u1; double t = ((u1.x - v1.x)*(v1.y - v2.y) - (u1.y - v1.y)*(v1.x - v2.x))/ ((u1.x - u2.x)*(v1.y - v2.y) - (u1.y - u2.y)*(v1.x - v2.x)); ans.x += (u2.x - u1.x)*t; ans.y += (u2.y - u1.y)*t; return ans; } void l2c_inst_p(point c,double r,point l1,point l2,point &p1,point &p2) { point p = c; double t; p.x += l1.y - l2.y; p.y += l2.x - l1.x; p = l2l_inst_p(p,c,l1,l2); t = sqrt(r*r - disp2p(p,c)*disp2p(p,c))/disp2p(l1,l2); p1.x = p.x + (l2.x - l1.x)*t; p1.y = p.y + (l2.y - l1.y)*t; p2.x = p.x - (l2.x - l1.x)*t; p2.y = p.y - (l2.y - l1.y)*t; } void c2c_inst_p(point c1,double r1,point c2,double r2,point &p1,point &p2) { point u,v; double t; t = (1 + (r1*r1 - r2*r2)/disp2p(c1,c2)/disp2p(c1,c2))/2; u.x = c1.x + (c2.x - c1.x)*t; u.y = c1.y + (c2.y - c1.y)*t; v.x = u.x + c1.y - c2.y; v.y = u.y - c1.x + c2.x; l2c_inst_p(c1,r1,u,v,p1,p2); } int ee; void cntee(point v,int n) { for(int i=0; i<n; i++) if( dd((v.x - c[i].a.x)*(v.x - c[i].a.x) + (v.y - c[i].a.y)*(v.y - c[i].a.y),c[i].r*c[i].r) ) ee++; } bool used[MAX]; void DFS(int x,int n) { for(int i=0; i<n; i++) if( !used[i] && ( c2c_inst(c[i],c[x]) || c2c_tangent(c[i],c[x]) ) ) { used[i] = true; DFS(i,n); } } int main() { int n,ncases; scanf("%d",&ncases); while( ncases-- ) { scanf("%d",&n); for(int i=0; i<n; i++) scanf("%lf%lf%lf",&c[i].a.x,&c[i].a.y,&c[i].r); int ans,cnt = 0,sum = 0; ee = 0; memset(used,false,sizeof(used)); for(int i=0; i<n; i++) if( !used[i] ) { used[i] = true; sum++; DFS(i,n); } for(int i=0; i<n; i++) for(int k=i+1; k<n; k++) { if( c2c_tangent(c[i],c[k]) ) p[cnt++] = c2c_tangent_p(c[i],c[k]); if( c2c_inst(c[i],c[k]) ) c2c_inst_p(c[i].a,c[i].r,c[k].a,c[k].r,p[cnt++],p[cnt++]); } sort(p,p+cnt,cmp); int nn = 0; if( cnt ) { cntee(p[0],n); nn = 1; } for(int i=1; i<cnt; i++) if( !dd(p[i].x,p[i-1].x) || !dd(p[i].y,p[i-1].y) ) { nn++; cntee(p[i],n); } ans = ee - nn + sum + 1; printf("%d\n",ans); } return 0; }