[几何 平面图欧拉定理] Codeforces 933C. A Colourful Prospect

平面图欧拉定理的应用

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>

using namespace std;

typedef double ld;

const ld eps=1e-7;

struct Point{
  ld x,y;
  Point(){}
  Point(ld _x,ld _y):x(_x),y(_y){}

  friend bool operator <(Point a,Point b){
    return a.x+eps<b.x || (fabs(a.x-b.x)<eps && a.y+eps<b.y);
  }

  friend bool operator ==(Point a,Point b){
    return fabs(a.x-b.x)<eps && fabs(a.y-b.y)<eps;
  }

  friend Point operator +(Point a,Point b){
    return Point(a.x+b.x,a.y+b.y);
  }

  friend Point operator -(Point a,Point b){
    return Point(a.x-b.x,a.y-b.y);
  }

  friend Point operator *(Point a,ld b){
    return Point(a.x*b,a.y*b);
  }

  friend Point operator *(ld b,Point a){
    return a*b;
  }

  friend Point operator /(Point a,ld b){
    return Point(a.x/b,a.y/b);
  }

  friend ld operator *(Point a,Point b){
    return a.x*b.x+a.y*b.y;
  }

  ld len(){
    return sqrt(x*x+y*y);
  }

  ld len2(){
    return x*x+y*y;
  }

  Point unit(){
    return *this/len();
  }

  Point normal(){
    return Point(-y,x);
  }
};

struct Line{
  Point l,r;
  Line(){}
  Line(Point _l,Point _r):l(_l),r(_r){}
};

struct Circle{
  Point o;
  ld r;
  Circle(){}
  Circle(Point _o,ld _r):o(_o),r(_r){}
};

vector<Point> gci(Circle a,Line b){
  Point h=a.o-(b.l-b.r).normal()*(a.o-b.l)/(b.l-b.r).len()*(b.l-b.r).normal().unit();
  if(fabs(a.r*a.r-(a.o-h).len2())<eps) return {h};
  double d=sqrt(a.r*a.r-(a.o-h).len2());
  return {h+(b.l-b.r).unit()*d,h-(b.l-b.r).unit()*d};
}

vector<Point> gci(Circle a,Circle b){
  ld dis=(a.o-b.o).len();
  if(dis>a.r+b.r+eps || dis+eps<fabs(a.r-b.r)) return {};
  ld k=((a.o-b.o).len2()+a.r*a.r-b.r*b.r)/2.0/(a.o-b.o).len();
  Point tmp=a.o+(b.o-a.o).unit()*k;
  Line t=Line(tmp,tmp+(b.o-a.o).normal());
  return gci(a,t);
}

int n,fa[5]; Circle a[5];

int getfa(int x){
  return x==fa[x]?x:fa[x]=getfa(fa[x]);
}

int main(){
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
  scanf("%d",&n);
  int e=0,v=0,l=0;
  for(int i=1;i<=n;i++)
    scanf("%lf%lf%lf",&a[i].o.x,&a[i].o.y,&a[i].r),fa[i]=i;
  vector<Point> Inter,kkk=gci(a[3],a[2]);
  for(int i=1;i<=n;i++){
    vector<Point> inter;
    for(int j=1;j<=n;j++)
      if(i!=j){
    vector<Point> cur=gci(a[i],a[j]);
    if(cur.size()==0) continue;
    fa[getfa(i)]=getfa(j);
    for(Point u : cur)
      Inter.push_back(u),inter.push_back(u);
      }
    sort(inter.begin(),inter.end());
    e+=unique(inter.begin(),inter.end())-inter.begin();
  }
  sort(Inter.begin(),Inter.end());
  //for(Point u : Inter)
  //  printf("%.6lf %.6lf\n",u.x,u.y);
  v=unique(Inter.begin(),Inter.end())-Inter.begin();
  for(int i=1;i<=n;i++)
    if(getfa(i)==i) l++;
  printf("%d\n",e-v+l+1);
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值