CodeForces - 32E Hide-and-Seek【计算几何】

题目链接:https://codeforces.com/contest/32/problem/E

先判两点之间是否被墙和镜子挡,再用相似三角形找入射点,乱搞判断一下。
这题有点卡精度,EPS用1e-6能过,1e-8过不了。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <climits>
#include <cstring>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <map>
#include <bitset>
#include <unordered_set>
#include <unordered_map>
#include <algorithm>
using namespace std;

#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define lowbit(x) (x & (-x))
#define CASET int _; scanf("%d", &_); for(int kase=1;kase<=_;kase++)

typedef double db;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;

static const int INF=0x3f3f3f3f;
static const ll INFL=0x3f3f3f3f3f3f3f3f;
static const db EPS=1e-6;
static const db PI=acos(-1.0);
static const int MOD=1e9+7;

template <typename T>
inline void read(T &f) {
    f = 0; T fu = 1; char c = getchar();
    while (c < '0' || c > '9') { if (c == '-') { fu = -1; } c = getchar(); }
    while (c >= '0' && c <= '9') { f = (f << 3) + (f << 1) + (c & 15); c = getchar(); }
    f *= fu;
}
template <typename T>
void print(T x) {
    if (x < 0) putchar('-'), x = -x;
    if (x < 10) putchar(x + 48);
    else print(x / 10), putchar(x % 10 + 48);
}
int sgn(db x){
    if(fabs(x)<EPS) return 0;
    if(x<0) return -1;
    return 1;
} // 符号函数 1正 -1负 0零 
int cmp(db x,db y){
    if(fabs(x-y)<EPS) return 0;
    if(x<y) return -1;
    return 1;
} // 比较函数 1大于 -1小于 0等于
struct Point{
    db x,y;
    Point(){}
    Point(db _x,db _y):x(_x),y(_y){}
    void input(){ scanf("%lf%lf",&x,&y); }
    bool operator==(const Point &b)const{ return sgn(x-b.x)==0 && sgn(y-b.y)==0; }
    bool operator<(const Point &b)const{ return sgn(x-b.x)==0?sgn(y-b.y)<0:x<b.x; }
    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 db &k)const{ return Point(x*k,y*k); }
    Point operator/(const db &k)const{ return Point(x/k,y/k); }
    db operator^(const Point &b)const{ return x*b.y-y*b.x; } // 叉积
    db operator*(const Point &b)const{ return x*b.x+y*b.y; } // 点积
    db len(){ return sqrt(x*x+y*y); } // 返回长度
    db len2(){ return x*x+y*y; } // 返回长度平方
    db distance(Point b){ return sqrt((x-b.x)*(x-b.x)+(y-b.y)*(y-b.y)); } // 返回两点距离
    db rad(Point a,Point b) {
        Point p=*this;
        return fabs(atan2(fabs((a-p)^(b-p)),(a-p)*(b-p)));
    } // 返回∠APB
    Point trunc(db r){
        db l=len();
        if(!sgn(l)) return *this;
        r/=l;
        return Point(x*r,y*r);
    } // 化为长度为r的向量
    Point rotate(Point p,db angle){
        Point v=(*this)-p;
        db c=cos(angle),s=sin(angle);
        return Point(p.x+v.x*c-v.y*s,p.y+v.x*s+v.y*c);
    } // 绕p点逆时针旋转angle
};
struct Line{
    Point s,e;
    Line(){}
    Line(Point _s,Point _e):s(_s),e(_e){}
    bool operator==(Line v){ return (s==v.s) && (e==v.e); }
    bool operator<(const Line &b){ return s<b.s; }
    Line(Point p,db angle) {
        s=p;
        if(!sgn(angle-PI/2)) e=(s+Point(0,1));
        else e=(s+Point(1,tan(angle)));
    } // 根据一个点p和倾斜角angle确定直线 0<=PI<PI
    Line(db a,db b,db c){
        if(!sgn(a)) s=Point(0,-c/b),e=Point(1,-c/b);
        else if(!sgn(b)) s=Point(-c/a,0),e=Point(-c/a,1);
        else s=Point(0,-c/b),e=Point(1,(-c-a)/b);
    } // ax+by+c==0;
    void input(){ s.input(); e.input(); }
    void adjust(){ if(e<s) swap(s,e); }
    db length(){ return s.distance(e); } // 求线段长度
    db angle(){
        db k=atan2(e.y-s.y,e.x-s.x);
        if(sgn(k)<0) k+=PI;
        if(!sgn(k-PI)) k-=PI;
        return k;
    } // 返回直线倾斜角 0<=angle<PI
    int relation(Point p){
        int c=sgn((p-s)^(e-s));
        if(c<0) return 1;
        else if(c>0) return 2;
        else return 3;
    } // 点和直线关系 1右侧 2左侧 3在直线上
    bool Pointonseg(Point p){ return !sgn((p-s)^(e-s)) && sgn((p-s)*(p-e))<=0; } // 判断点在线段上
    bool parallel(Line v){ return !sgn((e-s)^(v.e-v.s)); } // 判断两向量平行(两直线平行或重合)
    int segcrossseg(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);
    } // 两线段相交判断 2规范相交 1非规范相交 0不相交
    int linecrossseg(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;
    } // 直线和线段相交判断(-*this line -v seg) 2规范相交 1非规范相交 0不相交
    int linecrossline(Line v){
        if((*this).parallel(v)) return v.relation(s)==3;
        return 2;
    } // 两直线关系 0平行 1重合 2相交
    Point crosspoint(Line v){
        db a1=(v.e-v.s)^(s-v.s);
        db 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));
    } // 求两直线交点,需要保证两直线不平行或重合
    db dispointtoline(Point p){ return fabs((p-s)^(e-s))/length(); } // 点到直线距离
    db dispointtoseg(Point p){
        if(sgn((p-s)*(e-s))<0 || sgn((p-e)*(s-e))<0) return min(p.distance(s),p.distance(e));
        return dispointtoline(p);
    } // 求点到线段距离
    db dissegtoseg(Line v){ return min(min(dispointtoseg(v.s),dispointtoseg(v.e)),min(v.dispointtoseg(s),v.dispointtoseg(e))); } // 返回两线段的距离
    Point lineprog(Point p){ return s+(((e-s)*((e-s)*(p-s)))/(e-s).len2()); } // 返回点p在直线上的投影
    Point symmetrypoint(Point p){
        Point q=lineprog(p);
        return Point(2*q.x-p.x,2*q.y-p.y);
    } // 返回点p关于直线的对称点
};
static const int MAXP=40000+10;
struct Polygon{
    int n;
    Point p[MAXP];
    Line l[MAXP];
    void input(int _n){
        n=_n;
        for(int i=0;i<n;i++) p[i].input();
    }
    void add(Point q){ p[n++]=q; } // 插入一个点
    void getline(){ for(int i=0;i<n;i++) l[i]=Line(p[i],p[(i+1)%n]); } // 构造边
    struct cmp{
        Point p;
        cmp(const Point &p0):p(p0){}
        bool operator()(const Point &_a,const Point &_b){
            Point a=_a,b=_b;
            int d=sgn((a-p)^(b-p));
            if(!d) return sgn(a.distance(p)-b.distance(p))<0;
            return d>0;
        }
    };
    void norm(){
        Point mi=p[0];
        for(int i=1;i<n;i++) mi=min(mi,p[i]);
        sort(p,p+n,cmp(mi));
    } // 进行极角排序,首先需要找到最左下角的点,需要重载好Point的<操作符(min函数需要使用)
    void getconvex(Polygon &convex){
        sort(p,p+n);
        convex.n=n;
        for(int i=0;i<min(n,2);i++) convex.p[i]=p[i];
        if(convex.n==2 && (convex.p[0]==convex.p[1])) convex.n--; // 特判
        if(n<=2) return;
        int &top=convex.n;
        top=1;
        for(int i=2;i<n;i++){
            while(top && sgn((convex.p[top]-p[i])^(convex.p[top-1]-p[i]))<=0) top--;
            convex.p[++top]=p[i];
        }
        int tmp=top;
        convex.p[++top]=p[n-2];
        for(int i=n-3;i>=0;i--){
            while(top!=tmp && sgn((convex.p[top]-p[i])^(convex.p[top-1]-p[i]))<=0) top--;
            convex.p[++top]=p[i];
        }
        if(convex.n==2 && (convex.p[0]==convex.p[1])) convex.n--;
        // convex.norm(); // 原来得到的是顺时针的点,排序后逆时针
    } // 得到凸包法1
    void Graham(Polygon &convex){
        norm();
        int &top=convex.n;
        top=0;
        if(n==1){
            top=1; convex.p[0]=p[0]; return;
        }
        if(n==2){
            top=2; convex.p[0]=p[0]; convex.p[1]=p[1];
            if(convex.p[0]==convex.p[1]) top--;
            return;
        }
        top=2; convex.p[0]=p[0]; convex.p[1]=p[1];
        for(int i=2;i<n;i++){
            while(top>1 && sgn((convex.p[top-1]-convex.p[top-2])^(p[i]-convex.p[top-2]))<=0) top--;
            convex.p[top++]=p[i];
        }
        if(convex.n==2 && (convex.p[0]==convex.p[1])) convex.n--;
    } // 得到凸包法2
    bool isconvex(){
        bool s[3];
        memset(s,false,sizeof(s));
        for(int i=0;i<n;i++){
            int j=(i+1)%n;
            int k=(j+1)%n;
            s[sgn((p[j]-p[i])^(p[k]-p[i]))+1]=true;
            if(s[0] && s[2]) return false;
        }
        return true;
    } // 判断是否是凸包
    int relationpoint(Point q){
        for(int i=0;i<n;i++)
            if(p[i]==q) return 3;
        getline();
        for(int i=0;i<n;i++)
            if(l[i].Pointonseg(q)) return 2;
        int cnt=0;
        for(int i=0;i<n;i++){
            int j=(i+1)%n;
            int k=sgn((q-p[j])^(p[i]-p[j]));
            int u=sgn(p[i].y-q.y),v=sgn(p[j].y-q.y);
            if(k>0 && u<0 && v>=0) cnt++;
            if(k<0 && v<0 && u>=0) cnt--;
        }
        return cnt!=0;
    } // 判断点和凸包的关系 3 在点上 2 在边上 1 在内部 0 在外部
};
Point a,b;
Line l1,l2;
int main()
{
    a.input(); b.input();
    l1.input(); l2.input();
    if(!Line(a,b).segcrossseg(l1) && !Line(a,b).segcrossseg(l2)) puts("YES");
    else
    {
        Point t1=l2.symmetrypoint(a),t2=l2.symmetrypoint(b);
        Point c=(a+t1)/2.0,d=(b+t2)/2.0;
        db len1=a.distance(c),len2=b.distance(d);
        if(!sgn(len1) && !sgn(len2))
        {
            if(!Line(l2.s,a).segcrossseg(l1) && !Line(l2.s,b).segcrossseg(l1)) puts("YES");
            else puts("NO");
        }
        else
        {
            Point e=Point(c.x+(d.x-c.x)*len1/(len1+len2),c.y+(d.y-c.y)*len1/(len1+len2));
            if(l2.relation(a)==l2.relation(b) && l2.Pointonseg(e) && !Line(a,e).segcrossseg(l1) && !Line(b,e).segcrossseg(l1)) puts("YES");
            else puts("NO");
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值