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

A 来,求个三角形面积玩玩。
利用叉乘的特性就直接得到三角形的面积,如果三点共线则三点不构成三角形。此时叉乘结果为0.

#include<iostream>
#include<cstdio>
#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;
    }
};
int main()
{
    Point a,b,c;
    a.input();
    b.input();
    c.input();
    Point ab,cb;
    ab=Point(a-b);
    cb=Point(c-b);
    if(sgn(ab^cb)==0){
        printf("You're so funny\n");
    }
    else {
        printf("%.2lf\n",fabs(ab^cb)/2);
    }
}

B 我的玩具在哪里
这道题主要是判断点和线段的位置关系,根据每个点和每条线段的位置关系来判断这个点 在哪个位置里。

//点和直线的位置关系
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double inf = 1e20;
const int maxn = 5e3+10;
int sgn(double x){
    if(fabs(x)<0)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;
    }
};
struct Line{
    Point s,e;
    int relation(Point p){
        int c=sgn((p-s)^(p-e));
        if(c<0)return 1;
        else if(c>0)return 2;
        else return 3;
    }
};
Line l[maxn];
Point p[maxn];
int sum[maxn];
int main()
{
    int n,m;
    double x1,y1,x2,y2;
    int cnt=0;
    memset(sum,0,sizeof(sum));
    scanf("%d%d%lf%lf%lf%lf",&n,&m,&x1,&y1,&x2,&y2);
    for(int i=0;i<n;i++){
        double u,v;
        scanf("%lf%lf",&u,&v);
        l[i].s=Point(u,y1);
        l[i].e=Point(v,y2);
    }
    for(int i=0;i<m;i++){
        double x,y;
        scanf("%lf%lf",&x,&y);
        p[i]=Point(x,y);
    }
    for(int i=0;i<m;i++){
        for(int j=0;j<n;j++){
            if(l[j].relation(p[i])==1){
                sum[j]++;
                continue;
            }
        }
    }
    cnt=sum[0];
    for(int i=1;i<n;i++){
        cnt+=(sum[i]-sum[i-1]);
        //cout<<cnt<<endl;
    }
    //cout<<m<<" "<<cnt<<endl;
    sum[n]=m-cnt;
    for(int i=0;i<=n;i++){
        if(i>0&&i<n)
        printf("%d: %d\n",i,sum[i]-sum[i-1]);
        else printf("%d: %d\n",i,sum[i]);
    }
    return 0;
}

C 板子练习
上课讲的板子往上堆就可以啦。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
using namespace std;
const double eps = 1e-8;
const double inf = 1e20;
const double pi = acos(-1.0);
const int maxn = 1010;
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);
    }
    bool operator < (Point b)const{
        return sgn(x-b.x)==0?sgn(y-b.y)<0:x<b.x;
    }
    bool operator == (Point b)const{
        return sgn(x-b.x)==0&&sgn(y-b.y)==0;
    }
    Point operator + (const Point &b)const{
        return Point(x+b.x,y+b.y);
    }
    Point operator - (const Point &b)const{
        return Point(x-b.x,y-b.y);
    }
    Point operator / (const double &b)const{
        return Point (x/b,y/b);
    }
    Point operator * (const double &b)const{
        return Point (x*b,y*b);
    }
    double operator ^ (const Point &b)const{
        return x*b.y-y*b.x;
    }
    double operator * (const Point &b)const{
        return x*b.x+y*b.y;
    }
    double len(){
        return hypot(x,y);
    }
    double len2(){
        return x*x+y*y;
    }
    Point trunc(double r){
        double l=len();
        if(!sgn(l))return *this;
        r/=l;
        return Point(x*r,y*r);
    }
    Point rotleft(){
        return Point(-y,x);
    }
    Point rotright(){
        return Point(y,-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();
    }
    double legth(){
        return s.distance (e);
    }
    double angle(){
        double k=atan2(e.y-s.y,e.x-s.x);
        if(sgn(k)<0)k+=pi;
        if(sgn(k-pi)==0)k-=pi;
        return k;
    }
    Point cross_point(Line v){
        double a1 = (v.e-v.s)^(s-v.s);
        double a2 = (v.e-v.s)^(e-v.s);
        return Point ((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
    }
    double dis_point_to_line(Point p){
        return fabs((p-s)^(e-s))/legth();
    }
    double dis_point_to_seg(Point p){
        if(sgn((p-s)*(e-s))<0||sgn((p-e)*(s-e))<0)
        return min(p.distance(s),p.distance(e));
        return dis_point_to_line(p);
    }
    //返回点p在直线上的投影
    Point line_prog(Point p){
        return s+(((e-s)*((e-s)*(p-s)))/((e-s).len2()));
    }
    bool parallel (Line v){
        return sgn((e-s)^(v.e-v.s))==0;
    }
};
struct circle{
    Point p;
    double r;
    circle(){};
    circle(Point _p,double _r){
        p=_p;
        r=_r;
    }
    circle(double x,double y,double _r){
        p=Point(x,y);
        r=_r;
    }
    //三角形的外接圆
    circle(Point a,Point b,Point c){
        Line u = Line((a+b)/2,((a+b)/2)+((b-a).rotleft()));
        Line v = Line((b+c)/2,((b+c)/2)+((c-b).rotleft()));
        p = u.cross_point(v);
        r = p.distance(a);
    }
    //三角形内切圆
    circle(Point a,Point b,Point c,bool t){
        Line u,v;
        double m = atan2(b.y-a.y,b.x-a.x), n = atan2(c.y-a.y,c.x-a.x);
        u.s=a;
        u.e=u.s+Point(cos((n+m)/2),sin((n+m)/2));
        v.s=b;
        m=atan2(a.y-b.y,a.x-b.x), n= atan2(c.y-b.y,c.x-b.x);
        v.e = v.s+Point(cos((n+m)/2),sin((n+m)/2));
        p = u.cross_point(v);
        r = Line(a,b).dis_point_to_seg(p);
    }
    void input(){
        p.input();
        scanf("%lf",&r);
    }
    int relation_point(Point b){
        double dist = b.distance(p);
        if(sgn(dist - r)<0)return 2;
        else if(sgn(dist - r)==0) return 1;
        return 0;
    }
    //求直线和圆的交点
    int relation_line(Line v){
        double dist = v.dis_point_to_line(p);
        if(sgn(dist-r)<0)return 2;
        else if(sgn(dist-r)==0) return 1;
        return 0;
    }
    int relation_circle(circle v){
        double d = p.distance(v.p);
        if(sgn(d-r-v.r)>0)return 5;
        if(sgn(d-r-v.r)==0)return 4;
        double l =fabs(r-v.r);
        if(sgn(d-r-v.r)<0&&sgn(d-l)>0)return 3;
        if(sgn(d-l)==0)return 2;
        if(sgn(d-l)<0)return 1;
    }
    int point_cross_line(Line v,Point &p1,Point &p2){
        if(!(*this).relation_line(v))return 0;
        Point a = v.line_prog(p);
        double d = v.dis_point_to_line(p);
        d = sqrt(r*r-d*d);
        if(sgn(d)==0){
            p1=a;
            p2=a;
            return 1;
        }
        p1 = a+(v.e-v.s).trunc(d);
        p2 = a-(v.e-v.s).trunc(d);
        return 2;
    }
    int point_cross_circle(circle v,Point &p1,Point &p2){
        int rel = relation_circle(v);
        if(rel==1||rel==5)return 0;
        double d = p.distance(v.p);
        double l = (d*d+r*r-v.r*v.r)/(2*d);
        double h = sqrt(r*r-l*l);
        Point temp = p+(v.p-p).trunc(l);
        p1=temp + ((v.p-p).rotleft().trunc(h));
        p2=temp + ((v.p-p).rotright().trunc(h));
        if(rel == 2||rel ==4){
            return 1;
        }
        return 2;
    }
    int tangent_line(Point q,Line &u,Line &v){
        int x = relation_point(q);
        if(x==2) return 0;
        if(x==1){
            u=Line(q,q+(q-p).rotleft());
            v=u;
            return 1;
        }
        double d=p.distance (q);
        double l=r*r/d;
        double h=sqrt(r*r-l*l);
        u=Line(q,p+((q-p).trunc(l)+(q-p).rotleft().trunc(h)));
        v=Line(q,p+((q-p).trunc(l)+(q-p).rotright().trunc(h)));
        return 2;
    }
    //得过与直线u相切,过点q,半径为r1的圆
    int get_circle(Line u,Point q,double r1,circle &c1,circle &c2){
        double dis=u.dis_point_to_line(q);
        if(sgn(dis-r1*2)>0)return 0;
        if(sgn(dis)==0){
            c1.p=q+((u.e-u.s).rotleft().trunc(r1));
            c2.p=q+((u.e-u.s).rotright().trunc(r1));
            c1.r=c2.r=r1;
            return 2;
        }
        Line u1=Line((u.s+(u.e-u.s).rotleft().trunc(r1)),(u.e+(u.e-u.s).rotleft().trunc(r1)));
        Line u2=Line((u.s+(u.e-u.s).rotright().trunc(r1)),(u.e+(u.e-u.s).rotright().trunc(r1)));
        circle cc=circle(q,r1);
        Point p1,p2;
        if(!cc.point_cross_line(u1,p1,p2))cc.point_cross_line(u2,p1,p2);
        c1=circle(p1,r1);
        if(p1==p2){
            c2=c1;
            return 1;
        }
        c2=circle(p2,r1);
        return 2;
    }
    //同时与直线u,v相切,半径为r1的圆;
    int get_circle(Line u,Line v,double r1,circle &c1,circle &c2,circle &c3,circle &c4){
        if(u.parallel(v))return 0;
        Line u1=Line(u.s+(u.e-u.s).rotleft().trunc(r1),u.e+(u.e-u.s).rotleft().trunc(r1));
        Line u2=Line(u.s+(u.e-u.s).rotright().trunc(r1),u.e+(u.e-u.s).rotright().trunc(r1));
        Line v1=Line(v.s+(v.e-v.s).rotleft().trunc(r1),v.e+(v.e-v.s).rotleft().trunc(r1));
        Line v2=Line(v.s+(v.e-v.s).rotright().trunc(r1),v.e+(v.e-v.s).rotright().trunc(r1));
        c1.r=c2.r=c3.r=c4.r=r1;
        c1.p=u1.cross_point(v1);
        c2.p=u1.cross_point(v2);
        c3.p=u2.cross_point(v1);
        c4.p=u2.cross_point(v2);
        return 4;
    }
    //同时与不相交的两个圆cx,cy相切  ,半径为r1的圆
    int get_circle(circle cx,circle cy,double r1,circle &c1,circle &c2){
        circle x(cx.p,r1+cx.r),y(cy.p,r1+cy.r);
        int t=x.point_cross_circle(y,c1.p,c2.p);
        if(!t)return 0;
        c1.r=c2.r=r1;
        return t;
    }
};
int main()
{
    string s;
    while(cin>>s){
        if(s=="CircumscribedCircle"){
            Point a1,a2,a3;
            a1.input();
            a2.input();
            a3.input();
            circle ans(a1,a2,a3);
            printf("(%.6lf,%.6lf,%.6lf)\n",ans.p.x,ans.p.y,ans.r);
        }
        if(s=="InscribedCircle"){
            Point a1,a2,a3;
            a1.input();
            a2.input();
            a3.input();
            circle ans(a1,a2,a3,true);
            printf("(%.6lf,%.6lf,%.6lf)\n",ans.p.x,ans.p.y,ans.r);
        }
        if(s=="TangentLineThroughPoint"){
            circle c;
            c.input();
            Point pp;
            pp.input();
            Line uu,vv;
            int ans=c.tangent_line(pp,uu,vv);
            if(ans==0)printf("[]\n");
            if(ans==1)printf("[%.6lf]\n",uu.angle()/pi*180.0);
            if(ans==2){
                double res[5];
                res[0]=uu.angle();res[1]=vv.angle();
                sort(res,res+2);
                printf("[%.6lf,%.6lf]\n",res[0]/pi*180.0,res[1]/pi*180.0);
            }
        }
        if(s=="CircleThroughAPointAndTangentToALineWithRadius"){
            Point pp;
            pp.input();
            Line uu;
            uu.input();
            double rr;
            scanf("%lf",&rr);
            circle c,c1,c2;
            int ans=c.get_circle(uu,pp,rr,c1,c2);
            if(ans==0)printf("[]\n");
            if(ans==1)printf("[(%.6lf,%.6lf)]\n",c1.p.x,c1.p.y);
            if(ans==2){
                Point yx[5];
                yx[0]=c1.p;
                yx[1]=c2.p;
                sort(yx,yx+2);
                printf("[(%.6lf,%.6lf),(%.6lf,%.6lf)]\n",yx[0].x,yx[0].y,yx[1].x,yx[1].y);
            }
        }
        if(s=="CircleTangentToTwoLinesWithRadius"){
            Line u,v;
            double r1;
            circle c,c1,c2,c3,c4;
            u.input();
            v.input();
            scanf("%lf",&r1);
            c.get_circle(u,v,r1,c1,c2,c3,c4);
            Point yx[5];
            yx[0]=c1.p;
            yx[1]=c2.p;
            yx[2]=c3.p;
            yx[3]=c4.p;
            sort(yx,yx+4);
            printf("[(%.6lf,%.6lf),(%.6lf,%.6lf),(%.6lf,%.6lf),(%.6lf,%.6lf)]\n",
            yx[0].x,yx[0].y,yx[1].x,yx[1].y,yx[2].x,yx[2].y,yx[3].x,yx[3].y);
        }
        if(s=="CircleTangentToTwoDisjointCirclesWithRadius"){
            circle c,cx,cy,c1,c2;
            cx.input();
            cy.input();
            double r1;
            scanf("%lf",&r1);
            int ans=c.get_circle(cx,cy,r1,c1,c2);
            if(ans==0)printf("[]\n");
            if(ans==1)printf("[(%.6lf,%.6lf)]\n",c1.p.x,c1.p.y);
            if(ans==2){
                Point yx[5];
                yx[0]=c1.p;
                yx[1]=c2.p;
                sort(yx,yx+2);
                printf("[(%.6lf,%.6lf),(%.6lf,%.6lf)]\n",yx[0].x,yx[0].y,yx[1].x,yx[1].y);
            }
        }
    }
}

D 沙漠骆驼
这是一道判断线段相交和最短路的结合问题。
把每扇门(就是危险地带可以走的地方)看作是两个点然后利用计算几何的知识来判断一下两个点所形成的线段与图中的墙(也就是线段)有没有相交,规范相交与重合才算相交,对于不相交的两个点之间建立边,然后跑最短路就可以了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double inf = 1e20;
const int maxn = 1010;
int sgn(double x){
    if(fabs(x)<0)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;
    }
    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 operator * (const Point &b)const{
        return x*b.x+y*b.y;
    }
    double distance (Point b){
        return hypot(x-b.x,y-b.y);
    }
};
//两点距离
double dist(Point a,Point b)
{
    return sqrt((b-a)*(b-a));
}
struct Line{
    Point s,e;
    Line(){};
    Line(Point _s,Point _e){
        s=_s;e=_e;
    }
    Line(double x1,double y1,double x2,double y2){
        s.x=x1;s.y=y1;e.x=x2;e.y=y2;
    }
    //线段与线段相交判断
    //2 规范相交
    //1 非规范相交
    //0 不相交
    int seg_cross_seg(Line v){
        int d1 = sgn((e-s)^(v.s-s));
        int d2 = sgn((e-s)^(v.e-s));
        int d3 = sgn((v.e-v.s)^(s-v.s));
        int d4 = sgn((v.e-v.s)^(e-v.s));
        if((d1^d2)==-2&&(d3^d4)==-2) return 2;
        return (d1==0 &&sgn((v.s-s)*(v.s-e))<=0)||
               (d2==0 &&sgn((v.e-s)*(v.e-e))<=0)||
               (d3==0 &&sgn((s-v.s)*(s-v.e))<=0)||
               (d4==0 &&sgn((e-v.s)*(e-v.e))<=0);
    }
    int relation(Point p){
        int c=sgn((p-s)^(p-e));
        if(c<0)return 1;
        else if(c>0) return 2;
        else return 3;
    }
    bool parallel(Line v){
        return sgn((e-s)^(v.e-v.s))==0;
    }
    //直线与直线相交判断
    //0 平行
    //1 重合
    //2 相交
    int line_cross_line(Line v){
        if((*this).parallel(v))
        return v.relation(s)==3;
        return 2;
    }
};
struct edge{
    int ss,ee;
    double w;
    int next;
};
struct qnode{
    double dist;
    int num;
    bool operator < (const qnode &b)const{
        return dist>b.dist;
    }
};
edge e[maxn*maxn];
double dis[maxn];
int vis[maxn];
Point p[maxn];
Line s[maxn];
int head[maxn];
int cnt;
void add_edge(int ss,int ee,double ww){
    e[++cnt].ss=ss;e[cnt].ee=ee;e[cnt].w=ww;e[cnt].next=head[ss];head[ss]=cnt;
}
double dijkstra(int ss,int ee){
    priority_queue<qnode>q;
    qnode now,temp;
    dis[ss]=0;
    vis[ss]=1;
    now.dist=dis[ss];
    now.num=ss;
    q.push(now);
    while(!q.empty()){
        now=q.top();
        q.pop();
        vis[now.num]=0;
        for(int i=head[now.num];i!=-1;i=e[i].next){
            if(dis[e[i].ee]>now.dist+e[i].w){
                dis[e[i].ee]=now.dist+e[i].w;
                if(!vis[e[i].ee]){
                    temp.dist=dis[e[i].ee];
                    temp.num=e[i].ee;
                    q.push(temp);
                    vis[e[i].ee]=1;
                }
            }
        }
    }
    return dis[ee];
}
int main(){
    int n;
    scanf("%d",&n);
    cnt=0;
    fill(dis,dis+maxn,inf);
    memset(head,-1,sizeof(head));
    memset(vis,0,sizeof(vis));
    int p_cnt=0,s_cnt=0;
    for(int i=0;i<n;i++){
        double x,y[4];
        scanf("%lf%lf%lf%lf%lf",&x,&y[0],&y[1],&y[2],&y[3]);
        for(int j=0;j<4;j++){
            p[p_cnt++]=Point(x,y[j]);
        }
        s[s_cnt++]=Line(x,0,x,y[0]);
        s[s_cnt++]=Line(x,y[1],x,y[2]);
        s[s_cnt++]=Line(x,y[3],x,10.0);
    }
    p[p_cnt++]=Point (10.0,5.0);
    p[p_cnt++]=Point (0.0,5.0);
    for(int i=0;i<p_cnt;i++){
        for(int j=0;j<p_cnt;j++){
            Line temp=Line(p[i],p[j]);
            int flag=0;
            for(int k=0;k<s_cnt;k++){
                if(temp.seg_cross_seg(s[k])==2){// 规范相交
                    flag=1;
                    break;
                }
                if(temp.seg_cross_seg(s[k])==1){ //非规范相交要判断是否重合
                    if(temp.line_cross_line(s[k])==1){//如成立 说明重合
                        flag=1;
                        break;
                    }
                }
            }
            //cout<<i<<" "<<j<<" "<<flag<<" "<<g<<endl;
            if(!flag){
                add_edge(i,j,dist(p[i],p[j]));
                //cout<<e[cnt].ss<<" "<<e[cnt].ee<<" "<<e[cnt].w<<endl;
                add_edge(j,i,dist(p[i],p[j]));
                //cout<<e[cnt].ss<<" "<<e[cnt].ee<<" "<<e[cnt].w<<endl;
            }
        }
    }
    double ans = dijkstra(p_cnt-2,p_cnt-1);
    printf("%.2f\n",ans);

    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值