题目链接:click.
题意:
给你 k个卫星的坐标,m个靶子的坐标。问卫星能打到多少靶子。
卫星所能到达的最远距离是卫星与地球的切线距离.
通过作图观察得,地球圆心到达卫星与其能打击的靶子相连的线段的距离均为地球半径 r ,而与在射程范围外的靶子的距离都小于 r.
由此我们可以设卫星与靶子连成的线段到地球圆心的距离为 d
通过比较 d 与 r 大小可以知道该卫星是否能打到靶子.
代码:
#include<cmath>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN=1e3+5;
const double EPS=1e-6;
const double PI=acos(-1);
inline int sgn(double a){ return a < -EPS ? -1 : a > EPS; }
inline int cmp(double a, double b){ return sgn(a-b); }
int n,m,T;
struct Point3;
struct Line3;
typedef Point3 Vector3;
struct Point3{
double x,y,z;
Point3(){}
Point3(double a, double b, double c):x(a),y(b),z(c){}
double len(){return sqrt(x*x+y*y+z*z);}
double disToLine(Line3 l);
double disToSegment(Line3 l);
void read(){scanf("%lf%lf%lf",&x,&y,&z);}
Point3 operator+(Vector3 v){return {x+v.x,y+v.y,z+v.z};}
Vector3 operator-(Point3 p){return {x-p.x,y-p.y,z-p.z};}
Vector3 operator^(Vector3 v){return {y*v.z-z*v.y,z*v.x-x*v.z,x*v.y-y*v.x};}//叉乘
double operator*(Vector3 v){return x*v.x+y*v.y+z*v.z;}//点乘
bool operator==(Point3 p){return cmp(x,p.x)==0&&cmp(y,p.y)==0&&cmp(z,p.z)==0;}
};
struct Line3{
Point3 s,e;
};
double Point3::disToLine(Line3 l){
Vector3 v1=l.e-l.s,v2=*this-l.s;
return fabs((v1^v2).len())/(v1.len());
}
double Point3::disToSegment(Line3 l){
if(l.s==l.e) return (*this-l.s).len();
Vector3 v1 = l.e-l.s, v2 = *this-l.s, v3 = *this-l.e;
if(sgn(v1*v2) < 0) return v2.len();
if(sgn(v1*v3) > 0) return v3.len();
return disToLine(l);
}
Point3 goal[MAXN];
Point3 biu[MAXN];
bool vis[MAXN];
int k;
void solve(){
memset(vis,false, sizeof(vis));
double r=6366.197723676; //在样例里直接抄的(逃
Point3 o(0,0,0);//球心
int ans=0;
for(int i=1;i<=k;i++){
for(int j=1;j<=m;j++){
if(vis[j]) continue;
double d=o.disToSegment({biu[i],goal[j]});
if(cmp(d,r)>=0){
vis[j]=true;//把打过的标记一下
ans++;
}
}
}
printf("%d\n",ans);
}
void init(){
for(int i=1;i<=k;i++)
biu[i].read();
for(int i=1;i<=m;i++)
goal[i].read();
}
int main(){
while(~scanf("%d%d",&k,&m)&&(k||m)){
init();
solve();
}
return 0;
}