zoukankan      html  css  js  c++  java
  • 计算几何学习笔记

    前置

    实数

    类型:千万不要用\(float\),用\(double\)
    精度\(eps\)一般为\(1^{-8}\)\(1^{-9}\)
    比较:判断正负:

    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\)

    其中点积也可以表示为:\(|\vec a | |\vec b|\cos \theta\)
    叉积为:\(|\vec a||\vec b|\sin \theta\)
    其中\(\theta\)\(\vec a,\vec b\)夹角

    叉积既有正负,又有大小
    正负表示两个向量的位置关系,
    \(\vec a \times \vec b<0\),则a在b的逆时针方向,
    \(\vec a \times \vec b>0\),则a在b的顺时针方向
    \(\vec a \times \vec b=0\),则a、b同向或反向

    大小表示以\(\vec a,\vec b\)为邻边围成的平行四边形面积

    直线

    表示:点向法:点+向量
    向量垂直:$(x,y)\rightarrow (-y,x)/(y,-x) $

    判断点在直线上:叉积为\(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°

    极角


    参照点与选定点的连线与x轴的角度\((0\thicksim 2\pi)\)

    极角排序

    选定一点,把其它点相对于选定点的极角按大小排序
    一般选定左下角的点

    Graham算法

    先找到左下角的点,其它点排序后,枚举选出合法的,除去不合法的
    用叉积判断是否合法

    模板:

    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])));
    	}
    }
    

    最小矩阵

    定义:能够把所有的点都包括的面积最小的矩阵
    流程

    1. 求凸包
    2. 枚举下边界,去找左右上边界
    3. 更新答案

      \(i,i+1\)为下边界,\(r\)为最右边的点
      \(l\)为最左边的点,\(p\)为最上边的点
      易知,\(r\)为点积最大的点,\(l\)为点积最小的点,\(p\)为叉积最大的点

    代码:

    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]);
    		}
    	}
    }
    

    半平面交

    链接:[CQOI2006]凸多边形

  • 相关阅读:
    flask为blueprint增加error_handler
    solr的moreLikeThis实现“相似数据”功能
    pgsql删除重复记录
    sqlalchemy的不区分大小写比较
    logrotate运行时间指定
    远程桌面剪贴板失效的解决方法
    github上关于campbell数据采集的一些代码。
    python 学习笔记
    guestfs-python 手册
    [KVM][guestfs] 安装 guestfs-python 出错
  • 原文地址:https://www.cnblogs.com/heower/p/8460691.html
Copyright © 2011-2022 走看看