2019 SUST暑期集训题解(计算几何(二))

A . 梦想成为天文学家
这道题是一个原题,我们要用向量的知识来解决它,求解的就是四点共面。

//四个点三个向量 构成一个行列式 行列式的结果为0则共面否则不共面
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct p{
    int x,y,z;
}P[5];
p s[5];
int main()
{
    int t,cnt=0;
    scanf("%d",&t);
    while(t--){
        for(int i=1;i<=4;i++)
        {
            scanf("%d %d %d",&P[i].x,&P[i].y,&P[i].z);
        }
        s[1].x=P[2].x-P[1].x;
        s[1].y=P[2].y-P[1].y;
        s[1].z=P[2].z-P[1].z;
        s[2].x=P[3].x-P[1].x;
        s[2].y=P[3].y-P[1].y;
        s[2].z=P[3].z-P[1].z;
        s[3].x=P[4].x-P[1].x;
        s[3].y=P[4].y-P[1].y;
        s[3].z=P[4].z-P[1].z;
        int ans;
        ans=s[1].x*s[2].y*s[3].z+s[2].x*s[3].y*s[1].z+s[1].y*s[2].z*s[3].x-s[3].x*s[2].y*s[1].z-s[2].x*s[1].y*s[3].z-s[1].x*s[2].z*s[3].y;
        if(ans==0){
            cout<<"Day #"<<++cnt<<": "<<"Yes"<<endl;
        }
        else{
            cout<<"Day #"<<++cnt<<": "<<"No"<<endl;
        }
    }
    return 0;
}

B 线段的投影
这道题是一个二维几何的题目,要求解的多线段是否在同一条直线上的投影互相之间至少有一个交点。
其实两个线段必定可以找一个角度使得其投影在直线上有交点,所以我们就可以通过枚举两个线段的端点所构成直线的方式来判断,如果枚举一条直线可以与所有线段相交,即可证明所有的线段可以在同一条直线上的投影有公共点。
特判:
只有一个点或两个点时,一定可以找到一条直线。
还有就是对于枚举的点 两点距离小于1e-8 的点可以看成同一点不必枚举。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const double eps = 1e-8;
int sgn(double x){
    if(fabs(x)<eps)return 0;
    if(x<0)return -1;
    else return 1;
}
struct Point {
    double x,y;
    Point (){};
    Point (double _x,double _y){
        x=_x,y=_y;
    }
    void input(){
        scanf("%lf%lf",&x,&y);
    }
    Point operator - (const Point &b)const{
        return Point (x-b.x,y-b.y);
    }
    double operator ^ (const Point &b)const{
        return x*b.y-y*b.x;
    }
    double distance (Point p){
		return hypot(x-p.x,y-p.y);
	}
};
struct Line{
    Point s,e;
    Line(){};
    Line(Point _s,Point _e){
        s=_s;e=_e;
    }
    void input(){
        s.input();
        e.input();
    }
    int line_cross_seg(Line v){
        int d1 = sgn((e-s)^(v.s-s));
        int d2 = sgn((e-s)^(v.e-s));
        if((d1^d2) == -2)return 2;
        return (d1==0||d2==0);
    }
};
Line l[110];
bool judge(Line v,int n){
    for(int i=0;i<n;i++){
        //cout<<v.line_cross_seg(l[i])<<endl;
        if(v.line_cross_seg(l[i])==0)return false;
    }
    return true;
}
int main(){
    int t,n;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            l[i].input();
        }
        if(n==1){
            printf("Yes!\n");
            continue;
        }
        int flag=0;
        for(int i=0;i<n;i++){
            for(int j=i+1;j<n;j++){
                bool ans1,ans2,ans3,ans4;
                if(l[i].s.distance(l[j].s)>eps)
                ans1=judge(Line(l[i].s,l[j].s),n);
                if(l[i].s.distance(l[j].e)>eps)
                ans2=judge(Line(l[i].s,l[j].e),n);
                if(l[i].e.distance(l[j].s)>eps)
                ans3=judge(Line(l[i].e,l[j].s),n);
                if(l[i].e.distance(l[j].e)>eps)
                ans4=judge(Line(l[i].e,l[j].e),n);
                //cout<<ans1<<ans2<<ans3<<ans4<<endl;
                if(ans1||ans2||ans3||ans4){
                    flag=1;
                    break;
                }
                if(flag)break;
            }
        }
        if(flag)printf("Yes!\n");
        else printf("No!\n");
    }
    return 0;
}


C叉乘来了。
简单的叉乘求法向量

#include<iostream>
#include<cstdio>
using namespace std;
struct point{
    double x,y,z;
    point(){};
    point(double _x,double _y,double _z){
        x=_x;
        y=_y;
        z=_z;
    }
    void input(){
        scanf("%lf%lf%lf",&x,&y,&z);
    }
    void output(){
        printf("%.2lf %.2lf %.2lf\n",x,y,z);
    }
    point operator ^ (const point &b)const{
        return point (y*b.z-z*b.y,z*b.x-x*b.z,x*b.y-y*b.x);
    }
};
int main(){
    point a,b,c;
    a.input();
    b.input();
    c=a^b;
    c.output();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值