题意:给出三个点,求将二维平面划分成几部分。

题解:

感谢quailty的出题以及题解。
首先是常规的欧拉公式:

其中,表示划分成的平面数,为边数(edge),为顶点数(vertices)。

这里,将其进行变形。

表示整个图形的圆弧数,对单个圆来说,等于圆的上的交点数,求和即可求出,

表示所有圆产生的交点数,我们可以将所有两两圆的交点插入set中,set.size()即为

表示有几个联通的部分,用图的传递闭包解决,将有交点的圆之间设为联通,然后进行传递闭包,最后根据联通数即可求出

欧拉公式变形为:

对于单独存在,即不与其他的圆相交的圆,我们将其看作一个点和一个圆弧(边)构成。

代码:

#include<bits/stdc++.h>
#define N 1000010
#define INF 0x3f3f3f3f
#define LL long long
#define pb push_back
#define cl clear
#define si size
#define lb lowwer_bound
#define eps 1e-8
const LL P=1e9+7;
#define IO ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define P 1000000007;
using namespace std;
int dcmp(double x){if (fabs(x)<eps)return 0;else return x<0?-1:1;}
struct Point
{
    double x,y;
    bool operator < (const Point &a)const
    {return dcmp(x-a.x)<0 || (dcmp(x-a.x)==0 && dcmp(y-a.y)<0);}
    Point(double x=0,double y=0):x(x),y(y){ }

};

int n;
typedef Point Vector;
struct Circle
{
    Point c;
    double r;
    Circle(Point c=Point(0,0), double r=0):c(c),r(r){}
    Point point(double a)
    {
        return Point(c.x+cos(a)*r,c.y+sin(a)*r);
    }
}a[4];

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 b){return Vector(a.x*b,a.y*b);}
Vector operator / (Vector a,double b){return Vector(a.x/b,a.y/b);}
bool operator == (Vector a,Vector b){return dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0 ;}
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 Cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;} //叉积
double Angle(const 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(d - fabs(C1.r - C2.r)) < 0) return 0;
    if(dcmp(C1.r + C2.r - d) < 0) return 0;

    double a = Angle(C2.c - C1.c);               //向量C1C2的极角
    double da = acos((C1.r*C1.r + d*d - C2.r*C2.r) / (2*C1.r*d));
    //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;
}

set<Point> s[4];
set<Point>ss;
int f[4][4];

int main()
{
	cin>>n;
	for (int i=0;i<n;i++) cin>>a[i].c.x>>a[i].c.y>>a[i].r;
	if (n==1){
		cout<<2;
		return 0;
	}

	if (n==2){
		vector<Point>cc;
		int k=getCircleCircleIntersection(a[0],a[1],cc);
		if (k==0| k==1) cout<<3;else cout<<4;
		return 0;
	}

	for (int i=0;i<n;i++)
		for (int j=i+1;j<n;j++)
		{
			vector<Point>v;
			int k=getCircleCircleIntersection(a[i],a[j],v);
			for (int ii=0;ii<v.si();ii++) s[i].insert(v[ii]),
							s[j].insert(v[ii]),
							ss.insert(v[ii]);
			if (k>0) f[i][j]=f[j][i]=1;
		}

	for(int k=0;k<n;k++)
		for(int i=0;i<n;i++) if (i!=k)
			for (int j=0;j<n;j++) if (i!=j && k!=j)
				if (f[i][k] && f[k][j]) 
					f[i][j]=1;

	int c=3;
	for (int i=0;i<n;i++) 
		for (int j=i+1;j<n;j++) 
			if (f[i][j]) c--;
	if (!c) c++;

	for (int i=0;i<n;i++)
		if (s[i].si()==0)s[i].insert(Point{0,0}),
						 ss.insert(Point{i+100000,0});
	
	int e=0;
	for (int i=0;i<n;i++) e+=s[i].size();

	cout<<e-ss.si()+c+1;

    return 0;
}