#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<string>
#include<set>
#include<vector>
#include<map>
#define LL long long
using namespace std;
const double eps=5*1e-13;
const double PI=acos(-1.0);
int dcmp(double x)
{
if(fabs(x)<eps)
return 0;
return x>0?1:-1;
}
struct point
{
double x,y;
point() {}
point(double x,double y):x(x),y(y){}
point operator + (const point &a) const
{
return point(x+a.x,y+a.y);
}
point operator - (const point &a) const
{
return point(x-a.x,y-a.y);
}
point operator * (const double &a) const
{
return point(x*a,y*a);
}
point operator / (const double &a) const
{
return point(x/a,y/a);
}
bool operator <(const point &a) const
{
return (x+eps<a.x||(!dcmp(x-a.x)&&y<a.y));
}
double len()
{
return sqrt(x*x+y*y);
}
point normal()
{
return point(-y,x)/len();
}
void in()
{
cin>>x>>y;
}
};
double dis(point a,point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double angle(point v)
{
return atan2(v.y,v.x);
}
struct Circle
{
point o;
double r;
Circle() {}
Circle(point o,double r):o(o),r(r){}
point getpoint(double a)
{
return point(r*cos(a),r*sin(a))+o;
}
void in()
{
o.in();
cin>>r;
}
};
void getCircleCircleIntersection(Circle C1,Circle C2,vector<double> &sol)
{
point u=C1.o-C2.o;
double d=u.len();
if(dcmp(d)==0) return ;
if(dcmp(C1.r+C2.r-d)<0) return ;
if(dcmp(fabs(C1.r-C2.r)-d)>0) return ;
double a=angle(C2.o-C1.o);
double da=acos((C1.r*C1.r+d*d-C2.r*C2.r)/(2*C1.r*d));
sol.push_back(a+da);
sol.push_back(a-da);
}
Circle C[110];
int n;
int topmost(point p)
{
// cout<<p.x<<" "<<p.y<<endl;
for(int i=n-1;i>=0;i--)
{
// cout<<dis(C[i].o,p)<<endl;
if(dis(C[i].o,p)<C[i].r) return i;
}
return -1;
}
int main()
{
while(cin>>n&&n)
{
for(int i=0;i<n;i++)
C[i].in();
set<int> ret;
for(int i=0;i<n;i++)
{
vector<double> sol;
for(int j=0;j<n;j++)
getCircleCircleIntersection(C[i],C[j],sol);
sol.push_back(0);
sol.push_back(PI*2);
sort(sol.begin(),sol.end());
for(int j=0;j<sol.size();j++)
{
// cout<<sol[j]<<endl;
double mid=(sol[j]+sol[j+1])/2.0;
for(int d=-1;d<=1;d+=2)
{
double r2=C[i].r-d*eps;
//cout<<r2<<endl;
point a(C[i].o.x+cos(mid)*r2,C[i].o.y+sin(mid)*r2);
int t=topmost(a);
if(t>=0) ret.insert(t);
}
}
}
cout<<ret.size()<<endl;
}
return 0;
}
本人比较弱,看到题之后没思路,找题解,题解解释如下:
平面上给n个圆盘,有先后顺序的叠放在一起,求最后有多少个是可见的。
只要没有被完全遮住就是可见的。
首先,要是我们能枚举所有的点,找到覆盖这个点的圆盘中,最上面的,那么这个圆一定时可见的,否则被遮住,那么它不是最上面的。
好了,那么只要给一个点,找到topmost那务必是符合要求的,
现在就想怎么找到所有符合要求的圆盘。
对一个可见的圆盘,它必定至少有一部分是可见的,这一部分,必定是由圆弧组成,对于这块圆弧组成的区域,再没有任何圆盘去覆盖,我们取区域内的一个点的topmost一定能找到它。1那我们就取弧的中点,偏向一点2怎么取到内部? r+-eps,不是加就是减,总之取多了没关系,没漏掉就好。(微小扰动没关系--+-eps一定还在内部)。
然后是,样例的点都精确到e-11了,eps显然要提高。
看了题解后,自己敲了一份代码,发现不对,DBUG了好久发现竟然是调用一个函数时忘记加括号了,由此来看,敲程序一定要认真,一点小错误都会导致满盘皆输。贴上我的代码: