• 计算几何 学习笔记


    当然这个东西不常考,学一点基本的就行

    叉积

    \(\vec a\times \vec b\),或者简写成 axb。

    \[a*b=x_1y_2-x_2y_1 \]

    并不满足交换律。

    这个可以这样理解,将 \(a\) 逆时针旋转到 \(b\) 的角度。所以如果 \(>0\) 那么 \(a\) 就在 \(b\) 的下方,否则就在上方。

    判断一个点在直线的哪边

    设这个直线是 \(PQ\),而且我要求 \(A\) 在直线的哪边。计算出直线的方向向量 \(v=PQ\),那么判断 \(v*PA\) 的正负性即可(\(>0\) 在下方,\(<0\) 在上方)。

    求点集的凸包

    用 Andrew 算法求出 \(n\) 个点的凸包。

    首先将它们以 \(x\) 为第一关键字,\(y\) 为第二关键字排序。那么最左边和最右边的点就一定会在凸包中。我们依次求出上凸包和下凸包。

    用一个栈维护现在的凸包点集,如果我们现在要加入一个新点 \(a\),我们就看加入它后可以弹出栈顶多少个点。用叉积去计算斜率,比较 \(s_{top},s_{top-1}\) 的斜率,和 \(a,s_{top-1}\) 的斜率即可,若凹下去了就弹栈。

    while(top>1 && cross(vet(sak[top-1],sak[top]),vet(sak[top-1],i))<0 )top--;
    

    求一个点是否在一个三角形内

    对于三角形 \(\bigtriangledown ABC\),和点 \(N\),我们看,是否 \(A,N\) 在直线 \(BC\) 同侧; \(B,N\) 在直线 \(AC\) 同侧;\(C,N\) 在直线 \(AB\) 同侧。三个都满足就是,否则就不在三角形内。

    求多边形的周长与面积

    周长:直接相邻两个点算距离,最后再加起来。

    面积:\(\Large S=\frac{1}2 |\sum\limits_{i=1}^np_i\times p_{i+1}|\)(如果 \(i=n\)\(i+1=1\)

    平衡树维护凸包

    CF70D。(当然下面的代码不是这一题的 233)

    #include<bits/stdc++.h>
    #define rep(i,x,y) for(int i=x;i<=y;++i)
    #define per(i,x,y) for(int i=x;i>=y;--i)
    #define lon long long
    #define lod long double
    #define iter set <drop> :: iterator
    using namespace std;
    const int n7=201234,inf=2e9;
    const lod eps=1e-12;
    struct drop{
    	lod x,y;
    	friend bool operator == (drop p,drop q){return p.x==q.x&&p.y==q.y;}
    	friend bool operator != (drop p,drop q){return !(p==q);}
    	friend bool operator < (drop p,drop q){return p.x==q.x?p.y<q.y:p.x<q.x;}
    	friend drop operator - (drop p,drop q){return (drop){p.x-q.x,p.y-q.y};}
    	friend lod operator * (drop p,drop q){return p.x*q.y-p.y*q.x;}
    }a[n7],infl,infr;
    struct iron{char typ;int t,l,r;}qt[n7];
    int n,T,vis[n7],ans[n7],xmax,ymax;
    set <drop> sut;
    
    int rd(){
    	int shu=0;bool fu=0;char ch=getchar();
    	while( !isdigit(ch) ){if(ch=='-')fu=1;ch=getchar();}
    	while( isdigit(ch) )shu=(shu<<1)+(shu<<3)+ch-'0',ch=getchar();
    	return fu?-shu:shu;
    }
    
    lod getK(drop p,drop q){
    	if(p.x==q.x)return inf;
    	return (p.y-q.y)/(p.x-q.x);
    }
    
    void print(iter it=sut.end()){
    	puts("------");
    	if(it==sut.end()){
    		it=sut.begin();
    		while(it!=sut.end())printf("%.0Lf %.0Lf\n",(*it).x,(*it).y),++it;
    	}
    	else printf("%.0Lf %.0Lf\n",(*it).x,(*it).y);
    }
    
    bool check(drop x,iter it){
    	if( *prev(it)==infl || *it==infr )return 1;
    	drop p=*prev(it),q=*it;
    	drop z1=p-q,z2=x-p;
    	return z1*z2+eps<0;
    }
    
    void work(drop x){
    	if( sut.count(x) )return;
    	iter it=sut.lower_bound(x);
    	if( !check(x,it) )return;
    	while( *it!=infr && *next(it)!=infr ){
    		if( getK(*it,x)<=getK(*next(it),x) )++it,sut.erase( prev(it) );
    		else break;
    	}
    	it=--sut.lower_bound(x);
    	while( *it!=infl && *prev(it)!=infl ){
    		if( getK(*it,x)>=getK(*prev(it),x) )--it,sut.erase( next(it) );
    		else break;		
    	}
    	sut.insert(x);
    }
    
    int main(){
    	n=rd();
    	rep(i,1,n)a[i]=(drop){rd(),rd()};
    	T=rd();
    	rep(i,1,T){
    		char sys=getchar();
    		while( !isalpha(sys) )sys=getchar();
    		if(sys=='c')qt[i]=(iron){'c',rd(),rd(),rd()};
    		if(sys=='q')qt[i]=(iron){'q',rd()},vis[ qt[i].t ]=1;
    	}
    	infl=(drop){-inf,-inf},infr=(drop){inf,-inf};
    	sut.insert(infl),sut.insert(infr);
    	rep(i,1,n){
    		if(vis[i])continue;
    		work(a[i]);
    		if(a[i].y>ymax)xmax=a[i].x,ymax=a[i].y;
    	}
    	per(i,T,1){
    		if(qt[i].typ=='c'){
    			drop z=(drop){qt[i].l*1.0/qt[i].t,qt[i].r*1.0/qt[i].t};
    			if(z.x<=xmax&&z.y<=ymax)ans[i]=1;
    			else if( sut.count(z) )ans[i]=1;
    			else{
    				iter it=sut.lower_bound(z);
    				ans[i]=!check(z,it);
    			}
    		}
    		if(qt[i].typ=='q'){
    			work(a[ qt[i].t ]);
    			if(a[ qt[i].t ].y>ymax)xmax=a[ qt[i].t ].x,ymax=a[ qt[i].t ].y;
    		}
    	}
    	rep(i,1,T)if(qt[i].typ=='c')puts(ans[i]?"no":"yes");
    	return 0;
    }
    
    

    旋转卡壳

    双指针维护两个端点即可。

    详细一点:设定两个指针 \(i,j\),如果 \(dis(i,j)<dis(i,j+1)\) 那么 \(j++\),否则 \(i++\)

  • 相关阅读:
    Java的学习笔记(二)
    Java的学习笔记
    简单界面生成
    登录界面
    播放器
    java计划
    求和
    修改后的抽奖系统
    第十周作业
    JAVA第五次作业
  • 原文地址:https://www.cnblogs.com/BlankAo/p/16086969.html
Copyright © 2020-2023  润新知