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;
}
标签:return,Point,int,32E,db,CodeForces,sgn,Hide,const 来源: https://blog.csdn.net/inv00ker/article/details/116331064