17.8.19 校内赛 解题报告【求线段交点+凸包+求多边形面积】【判定点是否在多边形内】【二分答案+半平面交】

Problem 1. land

解题报告
显然,这道题就是线段求交点+凸包+求多边形面积
问题就是我们只有直线求交点的模板和判线段相交的模板,没有直接求线段相交的。我是这样解决的:先判断两线段是否相交,然后再把线段存储为直线,求出两者的交点。
代码如下:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define Point Vector
#define NAME "land"
using namespace std;
const double eps=1e-8;
const int N=1000;
int sign(double a){return a>eps?1:(a<-eps?-1:0);}
struct Vector
{
    double x,y;
    double len(){return sqrt(x*x+y*y);}
    double ang(){return atan2(y,x);}
    Vector(double a=.0,double b=.0):x(a),y(b){}
    Vector operator+(const Vector &s){return Vector(x+s.x,y+s.y);}
    Vector operator-(const Vector &s){return Vector(x-s.x,y-s.y);}
    Vector operator*(double s){return Vector(x*s,y*s);}
    Vector operator/(double s){return Vector(x/s,y/s);}
};
struct Seg
{
    Point A,B;
    Seg(){}
    Seg(Point a,Point b):A(a),B(b){}
}Segs[N+5];
struct Line
{
    Point p;
    Vector u;
    double ang;
    Line(){}
    Line(Point p,Vector v):p(p),u(v),ang(u.ang()){}
    bool operator<(const Line &s){return ang<s.ang;}
    bool operator==(const Line &s){return sign(ang-s.ang)==0;}
};
bool cmp(Point r,Point s)
{
    if(r.x==s.x)return r.y<s.y;
    return r.x<s.x;
}
double dot(const Vector &a,const Vector &b){return a.x*b.x+a.y*b.y;}//向量点积 
double cross(const Vector &a,const Vector &b){return a.x*b.y-a.y*b.x;}//向量叉积
bool onleft(Point a,Point b,Point p)
{
    return sign(cross(b-a,p-a))>0;
}
bool onleft(Line l,Point p)
{
    return sign(cross(l.u,p-l.p))>0;
}
vector<Point>convex(vector<Point>pts)//求凸包 
{
    int n=(int)pts.size(),m=0;
    vector<Point>cvx;
    sort(pts.begin(),pts.end(),cmp);
    for(int i=0;i<n;i++)
    {
        while(m>1&&onleft(cvx[m-2],cvx[m-1],pts[i])){cvx.pop_back();m--;}
        cvx.push_back(pts[i]);m++;
    }
    int k=m;
    for(int i=n-2;i>=0;i--)
    {
        while(m>k&&onleft(cvx[m-2],cvx[m-1],pts[i])){cvx.pop_back();m--;}
        cvx.push_back(pts[i]);m++;
    }
    if(n>1){m--;cvx.pop_back();}
    return cvx;
}
double area(vector<Point>poly)//求多边形的面积 
{
    double rt=0.0;
    int n=(int)poly.size();
    for(int i=0;i<n;i++)rt+=cross(poly[i],poly[(i+1)%n]);
    return fabs(rt/2.0);
}
Point line_intersect(Point P,Vector u,Point Q,Vector v) 
{
    double t=cross(Q-P,v)/cross(u,v);
    return P+u*t;
}
Point line_intersect(const Line &a,const Line &b)//求出两直线交点 
{
    return line_intersect(a.p,a.u,b.p,b.u);
}
bool seg_intersect(Point A,Point B,Point C,Point D)//判定两线段(AB,CD)是否相交 
{
    double c1=cross(B-A,C-A),c2=cross(B-A,D-A);
    double c3=cross(D-C,A-C),c4=cross(D-C,B-C);
    return sign(c1)*sign(c2)<0&&sign(c3)*sign(c4)<0;
}
int n;
vector<Point>pts,poly; 
int main()
{
    freopen(NAME".in","r",stdin);
    freopen(NAME".out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        double x1,y1,x2,y2;
        scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
        Segs[i]=Seg(Point(x1,y1),Point(x2,y2));
    }
    for(int i=1;i<=n-1;i++)
    for(int j=i+1;j<=n;j++)
    {
        if(seg_intersect(Segs[i].A,Segs[i].B,Segs[j].A,Segs[j].B))
        pts.push_back(line_intersect(Line((Segs[i].A),Segs[i].B-Segs[i].A),Line((Segs[j].A),Segs[j].B-Segs[j].A)));
    }
    poly=convex(pts);
    double ans=area(poly);
    printf("%.2lf",ans);
    return 0;
}

Problem 2. escape

解题报告
直接套模板上:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define Point Vector
#define NAME "escape"
using namespace std;
const double eps=1e-8;
int sign(double a){return a>eps?1:(a<-eps?-1:0);}
struct Vector
{
    double x,y;
    double len(){return sqrt(x*x+y*y);}
    double ang(){return atan2(y,x);}
    Vector(double a=.0,double b=.0):x(a),y(b){}
    Vector operator+(const Vector &s){return Vector(x+s.x,y+s.y);}
    Vector operator-(const Vector &s){return Vector(x-s.x,y-s.y);}
    Vector operator*(double s){return Vector(x*s,y*s);}
    Vector operator/(double s){return Vector(x/s,y/s);}
};
double dot(const Vector &a,const Vector &b){return a.x*b.x+a.y*b.y;}//向量点积 
double cross(const Vector &a,const Vector &b){return a.x*b.y-a.y*b.x;}//向量叉积
bool point_on_line(Point p,Point A,Point B)//判定点是否在线段上 
{
    return sign(cross(B-A,p-A))==0&&sign(dot(A-p,B-p))<=0;
}
bool in_polygon(Point p,vector<Point>poly)//判定点是否在多边形内 
{
    int n=(int)poly.size();
    int counter=0;
    for(int i=0;i<n;++i)
    {
        Point a=poly[i],b=poly[(i+1)%n];
        if(point_on_line(p,a,b))return true; // bounded included
        int x=sign(cross(p-a,b-a));
        int y=sign(a.y-p.y);
        int z=sign(b.y-p.y);
        if(x>0&&y<=0&&z>0)counter++;
        if(x<0&&z<=0&&y>0)counter--;
    }
    return counter!=0;
}
int n,q;
vector<Point>poly;
int main()
{
    freopen(NAME".in","r",stdin);
    freopen(NAME".out","w",stdout);
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
    {
        double x,y;
        scanf("%lf%lf",&x,&y);
        poly.push_back(Point(x,y));
    }
    while(q--)
    {
        double x,y;
        scanf("%lf%lf",&x,&y);
        if(in_polygon(Point(x,y),poly))printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

Problem 3. island

解题报告
这是蓝书上的例题,可以看我的这篇博客
代码如下:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define NAME "island"
#define Point Vector
using namespace std;
const double eps=1e-8;
const int N=1e5;
int sign(double a){return a>eps?1:(a<-eps?-1:0);}
struct Vector
{
    double x,y;
    double len(){return sqrt(x*x+y*y);}
    double ang(){return atan2(y,x);}
    Vector(double a=.0,double b=.0):x(a),y(b){}
    Vector operator+(const Vector &s){return Vector(x+s.x,y+s.y);}
    Vector operator-(const Vector &s){return Vector(x-s.x,y-s.y);}
    Vector operator*(double s){return Vector(x*s,y*s);}
    Vector operator/(double s){return Vector(x/s,y/s);}
};
Vector Normal(Vector a){double L=a.len();return Vector(-a.y/L,a.x/L);}
struct Line
{
    Point p;
    Vector u;
    double ang;
    Line(){}
    Line(Point p,Vector v):p(p),u(v),ang(u.ang()){}
    bool operator<(const Line &s){return ang<s.ang;}
    bool operator==(const Line &s){return sign(ang-s.ang)==0;}
    bool operator<(const Line&L)const{return ang<L.ang;}
};
double dot(const Vector &a,const Vector &b){return a.x*b.x+a.y*b.y;}//向量点积 
double cross(const Vector &a,const Vector &b){return a.x*b.y-a.y*b.x;}//向量叉积
Point line_intersect(Point P,Vector u,Point Q,Vector v) 
{
    double t=cross(Q-P,v)/cross(u,v);
    return P+u*t;
}
Point line_intersect(const Line &a,const Line &b)//求出两直线交点 
{
    return line_intersect(a.p,a.u,b.p,b.u);
}
bool seg_intersect(Point A,Point B,Point C,Point D)//判定两线段(AB,CD)是否相交 
{
    double c1=cross(B-A,C-A),c2=cross(B-A,D-A);
    double c3=cross(D-C,A-C),c4=cross(D-C,B-C);
    return sign(c1)*sign(c2)<0&&sign(c3)*sign(c4)<0;
}
bool cmp1(Line r,Line s)
{
    return r<s;
}
bool onleft(Point a,Point b,Point p)
{
    return sign(cross(b-a,p-a))>0;
}
bool onleft(Line l,Point p)
{
    return sign(cross(l.u,p-l.p))>0;
}
vector<Point>half_plane_intersect(vector<Line>L)
{
    int n=L.size();
    sort(L.begin(),L.end());
    int first,last;
    vector<Point> p(n);
    vector<Line> q(n);
    vector<Point> ans;
    q[first=last=0]=L[0];
    for(int i=1;i<n;i++)
    {
        while(first<last&&!onleft(L[i],p[last-1]))last--;
        while(first<last&&!onleft(L[i],p[first]))first++;
        q[++last]=L[i];
        if(fabs(cross(q[last].u,q[last-1].u))<eps)
        {
            last--;
            if(onleft(q[last],L[i].p))q[last]=L[i];
        }
        if(first<last)p[last-1]=line_intersect(q[last-1],q[last]);
    }
    while(first<last&&!onleft(q[first],p[last-1]))last--;
    if(last-first<=1)return ans;
    p[last]=line_intersect(q[last],q[first]);
    for(int i=first;i<=last;i++)ans.push_back(p[i]);
    return ans;
}
int n;
int main()
{
    freopen(NAME".in","r",stdin);
    freopen(NAME".out","w",stdout);
    scanf("%d",&n);
    vector<Point>p,v,normal;
    for(int i=1;i<=n;i++)
    {   
        double x,y;
        scanf("%lf%lf",&x,&y);
        p.push_back(Point(x,y));

    }
    for(int i=0;i<=n-1;i++)
    {
        v.push_back(p[(i+1)%n]-p[i]);
        normal.push_back(Normal(v[i]));
    }
    double lf=0,rg=20000;
    while(rg-lf>eps)
    {
        vector<Line>h;
        double mid=lf+(rg-lf)/2.0;
        for(int i=0;i<=n-1;i++)
        h.push_back(Line(p[i]+normal[i]*mid,v[i]));
        vector<Point>poly=half_plane_intersect(h);
        if(poly.empty())rg=mid;
        else lf=mid;
    }
    printf("%.2lf",lf);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值