类型:千万不要用\(float\),用\(double\)。
精度:\(eps\)通常为\(1^{-8}\)或\(1^{-9}\)。
比较:判断正负:html
int sign(int x){ return fabs(x)<=eps ? 0 : (x>0 ? 1 : -1); }
判断大小:
\(a>b \Rightarrow a-b>0\)
\(a<b \Rightarrow a-b<0\)
\(a==b \Rightarrow a-b==0\)算法
表示 :\((x,y)\)
运算:\((x_1,y_1),(x_2,y_2)\)
\(+\):\((x_1+x_2,y_1+y_2)\)
\(-\):\((x_1-x_2,y_1-y_2)\)
数乘:\((x\ast k,y\ast k)\)
点积:\(x_1\ast x2+y_1\ast y_2\)
叉积:\(x_1\ast y_2-x_2\ast y_1\)spa
其中点积也能够表示为:\(|\vec a | |\vec b|\cos \theta\)
叉积为:\(|\vec a||\vec b|\sin \theta\)
其中\(\theta\)为\(\vec a,\vec b\)夹角3d
叉积既有正负,又有大小
正负表示两个向量的位置关系,
若\(\vec a \times \vec b<0\),则a在b的逆时针方向,
若\(\vec a \times \vec b>0\),则a在b的顺时针方向
若\(\vec a \times \vec b=0\),则a、b同向或反向code
大小表示以\(\vec a,\vec b\)为邻边围成的平行四边形面积htm
表示:点向法:点+向量
向量垂直:$(x,y)\rightarrow (-y,x)/(y,-x) $blog
判断点在直线上:叉积为\(0\)
判断点在射线上:叉积为\(0\),点积\(\geq 0\)
判断点在线段上:叉积为\(0\),\(x_1\leq x_0 \leq x_2\)&&\(y_1\leq y_0 \leq y_2\)
点到直线距离:\(\frac{\vec a\times \vec b}{|\vec a|}\) 如图:
两直线交点:
\(p_0=p_2+v_2,s_1=\vec u \times \vec v_1,s_2=\vec v_1\times \vec v_2\)
\(k=\frac{s_1}{s_2}\)
\(p_0=p_2+kv_2\)排序
线段相交
\((\vec {AB}\times \vec{AC})\ast (\vec{AB}\times \vec{AD})\leq 0\)&&\((\vec{CD}\times \vec{CA})\ast(\vec{CD}\times \vec{CB})\leq 0\)继承
多边形的内角小于180°get
参照点与选定点的连线与x轴的角度\((0\thicksim 2\pi)\)
选定一点,把其它点相对于选定点的极角按大小排序
通常选定左下角的点
先找到左下角的点,其它点排序后,枚举选出合法的,除去不合法的
用叉积判断是否合法
模板:
int n; struct Point{ int x,y; friend Point operator + (Point a,Point b){//加法 Point t; t.x=a.x+b.x;t.y=a.y+b.y; return t; } friend Point operator - (Point a,Point b){//减法 Point t; t.x=a.x-b.x;t.y=a.y-b.y; return t; } friend double operator ^ (Point a,Point b){//叉积 return a.x*b.y-a.y*b.x; } friend double operator * (Point a,Point b){//点积 return a.x*b.x+a.y*b.y; } }a[N],s[N]; int top; int sign(ORZ x){ return fabs(x)<=eps ? 0 : (x>0 ? 1 : -1); } double dis(Point i,Point j){ return (i.x-j.x)*(i.x-j.x)+(i.y-j.y)*(i.y-j.y); } bool comp(Point i,Point j){ double x=(i-a[1])^(j-a[1]);//画图体验一下 return x>0||x==0&&dis(a[1],i)<dis(a[1],j); } void Graham(){ int k=1; F(i,2,n) if(a[i].y<a[k].y||(a[i].y==a[k].y&&a[i].x<a[k].x)) k=i; swap(a[k],a[1]); sort(a+2,a+n+1,comp); s[++top]=a[1];s[++top]=a[2]; F(i,3,n){ while(top>=2&&sign((s[top]-s[top-1]) ^ (a[i]-s[top-1]))<=0) top--; s[++top]=a[i]; } }
首先,最远的两点必定在凸包上
而且枚举点时,最远点是单调的
因此\(O(n)\)求出
观察发现,距离是单调的
能够枚举边,点从上一次继承过来
能够用面积表示,当下一个点与线段组成的面积比当前点小,就中止,更新一次答案
代码:
void work(){ if(top==2) return dis(s[1],s[2]); s[++top]=s[1]; int j=3; F(i,1,top-1){ while(((s[i+1]-s[i])^(s[j]-s[i])) < ((s[i+1]-s[i])^(s[j+1]-s[i]))){ //当下一个点与线段组成的面积大于这个点时更新 j++; if(j==top+1) j=1; } ans=max(ans,max(dis(s[i],s[j]),dis(s[i+1],s[j]))); } }
定义:可以把全部的点都包括的面积最小的矩阵
流程:
代码:
void Min_Mart(){ int l=1,r=1,p=1; double L,R,H;ans=1e50; F(i,0,top-1){ double d=dis(s[i],s[i+1]); while((((s[i+1]-s[i])^(s[p+1]-s[i]))-((s[i+1]-s[i])^(s[p]-s[i])))>-eps) (p+=1)%=top; //找最远点 while(((s[i+1]-s[i])*(s[r+1]-s[i])-(s[i+1]-s[i])*(s[r]-s[i]))>-eps) (r+=1)%=top; //找最右边的点 if(i==0) l=r; while(((s[i+1]-s[i])*(s[l+1]-s[i])-(s[i+1]-s[i])*(s[l]-s[i]))<eps) (l+=1)%=top; //找最左边的点 L=(s[i+1]-s[i])*(s[l]-s[i])/d; R=(s[i+1]-s[i])*(s[r]-s[i])/d; H=((s[i+1]-s[i])^(s[p]-s[i]))/d; H=fabs(H); double sum=fabs(R-L)*H; //求面积 if(sign(sum-ans)<0) { //计算点 ans=sum; t[0]=s[i]+(s[i+1]-s[i])*(R/d); t[1]=t[0]+(s[r]-t[0])*(H/dis(t[0],s[r])); t[2]=t[1]-(t[0]-s[i])*((R-L)/dis(s[i],t[0])); t[3]=t[2]-(t[1]-t[0]); } } }