使用方法,复制粘贴
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#define FastIo ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
typedef long long ll;
using namespace std;
const double eps = 1e-15;
const double PI = acos(-1.0);
int sgn(double x)
{
if(fabs(x)<eps)return 0;
if(x<0)return -1;
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;
}
bool operator == ( Point const&a )const {return sgn(a.x-x) == 0 && sgn(a.y-y) == 0;}
friend ostream & operator<<(ostream &o,const Point & p)
{
o<<p.x<<' '<<p.y;
return o;
}
friend istream & operator>>(istream &is,Point &P)
{
is>>P.x>>P.y;
return is;
}
void transXY(double B)
{//绕原点旋转角度B(弧度)后x,y的变化
double tx=x,ty=y;
x=tx*cos(B)-ty*sin(B);
y=tx*sin(B)+ty*cos(B);
}
};
struct Line
{
//(y2-y1)*x-(x2-x1)*y-x1*y2+x2*y1=0
//已知两点求直线的一般式
Point s,e;
Line(){}
Line(Point _s,Point _e)
{
s=_s;e=_e;
}
//两直线相交求交点
//第一个值为0表示直线重合,为1表示平行,为0表示相交,为2是相交
//只有第一个值为2时,交点才有意义
friend istream & operator>>(istream &is,Line &l)
{
is>>l.s>>l.e;
return is;
}
pair<int,Point>operator &(const Line &b)const
{
Point res=s;
if(sgn((s-e)^(b.s-b.e))==0)
{
if(sgn((s-b.e)^(b.s-b.e))==0)
return make_pair(0,res);//重合
else return make_pair(1,res);//平行
}
double t=((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e));
res.x+=(e.x-s.x)*t;
res.y+=(e.y-s.y)*t;
return make_pair(2,res);
}
};
Point InterPoint(Point A,Point B,Point C,Point D)
{//AB与CD交点
if(abs((A-B)^(C-B))<eps&&abs((A-B)^(D-B))<eps)
{
//共线
}
if((A-B).x*(C-D).y-(C-D).x*(A-B).y)
{
//平行
}
Point p;
double a1=A.y-B.y;
double b1=B.x-A.x;
double c1=A.x*B.y-B.x*A.y;
double a2=C.y-D.y;
double b2=D.x-C.x;
double c2=C.x*D.y-D.x*C.y;
p.x=(b1*c2-b2*c1)/(a1*b2-a2*b1);
p.y=(a2*c1-a1*c2)/(a1*b2-a2*b1);
return p;
}
double dist(Point a,Point b)
{
return sqrt((a-b)*(a-b));
}
bool inter(Line l1,Line l2)
{//线段相交
return
max(l1.s.x,l1.e.x)>=min(l2.s.x,l2.e.x)&&
max(l2.s.x,l2.e.x)>=min(l1.s.x,l1.e.x)&&
max(l1.s.y,l1.e.y)>=min(l2.s.y,l2.e.y)&&
max(l2.s.y,l2.e.y)>=min(l1.s.y,l1.e.y)&&//快速排斥试验 一定要有 否则无法判断平行和重合
sgn((l2.s-l1.e)^(l1.s-l1.e))*sgn((l2.e-l1.e)^(l1.s-l1.e))<=0&&
sgn((l1.s-l2.e)^(l2.s-l2.e))*sgn((l1.e-l2.e)^(l2.s-l2.e))<=0;//跨立实验 两条线段互相跨立
}
//跨立实验利用叉积的性质 判断自身的Line和判断对象的Line之间的关系
//线段之间需判断两次 线段和直线只需判断一次 并且只需判断线段是否跨立直线
bool Seg_inter_line(Line l1,Line l2)//直线l1 线段l2
{//判断直线与线段相交
return sgn((l2.s-l1.e)^(l1.s-l1.e))*sgn((l2.e-l1.e)^(l1.s-l1.e))<=0;
}
//点到直线距离
//返回为result,是点到直线最近的点
Point PointToLine(Point P,Line L)
{
Point result;
double t=((P-L.s)*(L.e-L.s))/((L.e-L.s)*(L.e-L.s));
result.x=L.s.x+(L.e.x-L.s.x)*t;
result.y=L.s.y+(L.e.y-L.s.y)*t;
return result;
}
//点到线段的距离
//返回点到线段最近的点
Point NearstPointToLineSeg(Point P,Line L)
{
Point result;
double t=((P-L.s)*(L.e-L.s))/((L.e-L.s)*(L.e-L.s));
if(t>=0&&t<=1)
{
result.x=L.s.x+(L.e.x-L.s.x)*t;
result.y=L.s.y+(L.e.y-L.s.y)*t;
}
else
{
if(dist(P,L.s)<dist(P,L.e))
result=L.s;
else result=L.e;
}
return result;
}
bool OnSeg(Point P,Line L)
{//判断点在线段上
return
sgn((L.s-P)^(L.e-P))==0&&
sgn((P.x-L.s.x)*(P.x-L.e.x))<=0&&
sgn((P.y-L.s.y)*(P.y-L.e.y))<=0;
}
//计算多边形面积
//点的编号从0~n-1
double CalcArea(Point p[],int n)
{
double res=0;
for(int i=0;i<n;i++)
res+=(p[i]^p[(i+1)%n])/2;
return fabs(res);
}
//*判断点在凸多边形内
//射线法
//1.需特判点在多边形上的情况
//2.对于多边形的水平边不作考虑
//3.过顶点如果是一条边上面的点才计数
int inConvexPoly(Point p,Point poly[],int n)
{//转角法
int wn=0;
for(int i=0;i<n;i++)
{
if(OnSeg(p,Line(poly[i],poly[(i+1)%n]))) return -1; //在边界上
int k=sgn((poly[(i+1)%n]-poly[i])^(p-poly[i]));
int d1=sgn(poly[i].y-p.y);
int d2=sgn(poly[(i+1)%n].y-p.y);
if(k>0 && d1<=0 && d2>0) wn++;
if(k<0 && d2<=0 && d1>0) wn--;
}
if(wn!=0) return 1; //内部
return 0; //外部
}
/*
* 求凸包, Graham算法
* 点的编号0~n-1
* 返回凸包结果Stack[0~top-1]为凸包的编号
*/
const int MAXN = 1010;
Point list[MAXN];
int Stack[MAXN],top;
//相对于list[0]的极角排序
bool _cmp(Point p1,Point p2)
{
double tmp = (p1-list[0])^(p2-list[0]);
if(sgn(tmp) > 0)return true;
else if(sgn(tmp) == 0 && sgn(dist(p1,list[0]) - dist(p2,list[0])) <= 0)
return true;
else return false;
}
void Graham(int n)
{
Point p0;
int k = 0;
p0 = list[0];
//找最下边的一个点
for(int i = 1;i < n;i++)
{
if( (p0.y > list[i].y) || (p0.y == list[i].y && p0.x > list[i].x) )
{
p0 = list[i];
k = i;
}
}
swap(list[k],list[0]);
sort(list+1,list+n,_cmp);
if(n == 1)
{
top = 1;
Stack[0] = 0;
return;
}
if(n == 2)
{
top = 2;
Stack[0] = 0;
Stack[1] = 1;
return ;
}
Stack[0] = 0;
Stack[1] = 1;
top = 2;
for(int i = 2;i < n;i++)
{
while(top>1&&sgn((list[Stack[top-1]]-list[Stack[top-2]])^(list[i]-list[Stack[top-2]]))<=0)
top--;
Stack[top++] = i;
}
}
bool isconvex(Point poly[],int n)
{
bool s[3];
memset(s,false,sizeof(s));
for(int i=0;i<n;i++)
{
s[sgn((poly[(i+1)%n]-poly[i])^(poly[(i+2)%n]-poly[i]))+1]=true;
if(s[0]&&s[2])return false;
}
return true;
}
const int N=1e6;
Point p[N];
int main()
{
FastIo
/**
code
*/
}