HDU - 1140 War on Weather(基础三维几何)

题目链接: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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值