网上很多代码太长,其实理解了之后会非常简单就写出来。
就是个合并的过程,相交的圆合并到一起,如果与上(下)边界相交就合并上(下)边界。
如果上下边界最后在同一个集合里说明通过不了。
然后是找出入口。同样很简单,如果一个圆与左边界相交,而它的集合中含有上边界,则更新答案(红点),因为上面围起来的部分是无法通过的。此时就不需要考虑下边界了。
至于判相交和找交点只需要非常简单的一些知识就可以了。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define exp 1e-9
#define S 1005
#define X 1006
#define INF 9999
using namespace std;
struct circle
{
double x,y,r;
};
circle s[1010];
int n;
int f[1010];
int find(int x)
{
if (f[x]==x) return x;
return f[x]=find(f[x]);
}
inline double dis(double x1,double y1,double x2,double y2)
{
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
bool jiao(circle a,circle b)
{
double d=dis(a.x,a.y,b.x,b.y);
return (d<a.r+b.r && fabs(d-a.r-b.r)>exp);
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) f[i]=i;
f[X]=X; f[S]=S;
for (int i=1;i<=n;i++)
{
scanf("%lf%lf%lf",&s[i].x,&s[i].y,&s[i].r);
for (int j=1;j<i;j++)
{
if (jiao(s[i],s[j]))
{
int fi=find(i),fj=find(j);
f[fj]=fi;
}
}
double dx=fabs(s[i].y),ds=fabs(s[i].y-1000);
if (dx<s[i].r && fabs(dx-s[i].r)>exp) f[find(X)]=f[find(i)];
if (ds<s[i].r && fabs(ds-s[i].r)>exp) f[find(i)]=f[find(S)];
}
if (find(X)==find(S)) printf("Bill will be bitten.");
else
{
double sy=1000,ey=1000;
for (int i=1;i<=n;i++)
{
double dz=fabs(s[i].x),dy=fabs(s[i].x-1000);
if (dz<s[i].r && fabs(dz-s[i].r)>exp && find(i)==find(S)) sy=min(sy,s[i].y-sqrt(s[i].r*s[i].r-dz*dz));
if (dy<s[i].r && fabs(dy-s[i].r)>exp && find(i)==find(S)) ey=min(ey,s[i].y-sqrt(s[i].r*s[i].r-dy*dy));
}
printf("Bill enters at (0.00, %0.2lf) and leaves at (1000.00, %0.2lf).",sy,ey);
}
return 0;
}