zoukankan      html  css  js  c++  java
  • 计算几何基础

    计算几何基础

    UVA11178 Morley's Theorem
    此题直接模拟即可,主要是熟悉向量基本运算

    #include<bits/stdc++.h>
    using namespace std;
    typedef double db;
    struct vec
    {
    	db x,y;
    	inline void read(){scanf("%lf%lf",&x,&y);}
    	inline void print(){printf("%.6lf %.6lf ",x,y);}
    };
    inline vec operator+(const vec&x,const vec&y){return {x.x+y.x,x.y+y.y};}//向量相加
    inline vec operator-(const vec&x,const vec&y){return {x.x-y.x,x.y-y.y};}//向量相减
    inline vec operator*(const db&x,const vec&y){return {x*y.x,x*y.y};}//向量数乘
    inline db dot(const vec&x,const vec&y){return x.x*y.x+x.y*y.y;}//向量点乘
    inline db cross(const vec&x,const vec&y){return x.x*y.y-x.y*y.x;}//向量叉乘
    inline db len(const vec&x){return sqrt(x.x*x.x+x.y*x.y);}//向量模长
    inline db ang(const vec&x,const vec&y){return acos(dot(x,y)/len(x)/len(y));}//向量夹角:dot(a,b)=|a||b|cos<a,b>
    inline vec inr(const vec&P,const vec&v,const vec&Q,const vec&w)
    {
    	vec u=P-Q;
    	double t1=cross(w,u)/cross(v,w);
    	return P+t1*v;
    }////直线焦点
    inline vec rot(const vec&x,db rad)
    {
    	return {x.x*cos(rad)-x.y*sin(rad),x.x*sin(rad)+x.y*cos(rad)};
    }//向量逆时针旋转rad
    inline vec solve(const vec&A,const vec&B,const vec&C)
    {
    	vec v1=C-B;
    	double a=ang(A-B,v1);
    	v1=rot(v1,a/3);
    	vec v2=B-C;
    	double b=ang(A-C,v2);
    	v2=rot(v2,-b/3);
    	return inr(B,v1,C,v2);
    }
    vec A,B,C,D,E,F;
    int main()
    {
    	int T;scanf("%d",&T);
    	while(T--)
    	{
    		A.read(),B.read(),C.read();
    		D=solve(A,B,C);
    		E=solve(B,C,A);
    		F=solve(C,A,B);
    		D.print(),E.print(),F.print();puts("");
    	}
    	return 0;
    }
    

    UVA1342 That Nice Euler Circuit
    求一个多边形把平面分成了多少个部分
    此题主要是欧拉定理

    [V+F-E=2 ]

    因此求出顶点个数和边数即可
    顶点个数可以线段两两求交后去重
    边数可以每发现一个点在边上就把边数加一,原因是它会把当前边新分割出一部分

    #include<bits/stdc++.h>
    using namespace std;
    typedef double db;
    const int N=305;
    const db eps=1e-7;
    inline int sig(const db&x){return fabs(x)<eps?0:(x<0?-1:1);}
    struct vec
    {
    	db x,y;
    	inline void read(){scanf("%lf%lf",&x,&y);}
    	inline void print(){printf("%.6lf %.6lf ",x,y);}
    }p[N],v[N*N];
    inline bool operator<(const vec&x,const vec&y){return x.x<y.x||(x.x==y.x&&x.y<y.y);}
    inline bool operator==(const vec&x,const vec&y){return sig(x.x-y.x)==0&&sig(x.y-y.y)==0;}
    inline vec operator+(const vec&x,const vec&y){return {x.x+y.x,x.y+y.y};}
    inline vec operator-(const vec&x,const vec&y){return {x.x-y.x,x.y-y.y};}
    inline vec operator*(const db&x,const vec&y){return {x*y.x,x*y.y};}
    inline db dot(const vec&x,const vec&y){return x.x*y.x+x.y*y.y;}
    inline db cross(const vec&x,const vec&y){return x.x*y.y-x.y*y.x;}
    inline vec inr(const vec&P,const vec&v,const vec&Q,const vec&w)
    {
    	vec u=P-Q;
    	double t1=cross(w,u)/cross(v,w);
    	return P+t1*v;
    }
    inline bool pd(const vec&a1,const vec&a2,const vec&b1,const vec&b2)
    {
    	db c1,c2,c3,c4;
    	c1=cross(a2-a1,b1-a1),c2=cross(a2-a1,b2-a1);
    	c3=cross(b2-b1,a1-b1),c4=cross(b2-b1,a2-b1);
    	return sig(c1)*sig(c2)<0&&sig(c3)*sig(c4)<0;
    }//判断两线段是否规范相交:每一条线段的两个端点都在另一条线段的两侧
    inline bool ons(const vec&p,const vec&a,const vec&b)
    {
    	return sig(cross(a-p,b-p))==0&&sig(dot(a-p,b-p))<0;
    }//判断点是否在线段上:叉积为0且和线段两端连线的夹角是钝角(准确来说应该是平角)
    int main()
    {
    	int kase=0,n;
    	while(scanf("%d",&n)==1&&n)
    	{
    		for(int i=1;i<=n;++i)p[i].read(),v[i]=p[i];
    		int c=n-1,e=n-1;
    		for(int i=1;i<n;++i)
    			for(int j=i+1;j<n;++j)
    				if(pd(p[i],p[i+1],p[j],p[j+1]))
    					v[++c]=inr(p[i],p[i+1]-p[i],p[j],p[j+1]-p[j]);
    		sort(v+1,v+c+1);
    		int tot=unique(v+1,v+c+1)-v-1;
    		for(int i=1;i<=tot;++i)
    			for(int j=1;j<n;++j)
    				if(ons(v[i],p[j],p[j+1]))++e;
    		printf("Case %d: There are %d pieces.
    ",++kase,e+2-tot);
    	}
    	return 0;
    }
    

    UVA12304 2D Geometry 110 in 1!
    任务一:求三角形外接圆
    中垂线求交点
    任务二:求三角形内切圆
    角平分线求交点
    任务三:过已知点求已知圆的切线
    可以通过点到圆心的距离判断解的个数

    容易求出(alpha),那么旋转一下就可以求出切线极角了
    任务四:求所有点满足到定直线距离为(r)且到定点距离为(r),其中(r)给定
    将定直线延其垂直方向平移(r)可得两条直线
    这两条直线和以定点为圆心,(r)为半径的圆求交点即可
    任务五:求到两定直线距离为(r)的点,其中(r)给定
    和任务四类似得到四条直线两两求交
    任务六:求所有半径为(r)且和两给定圆外切的圆的圆心
    将原先的两个圆的半径增加(r),然后再求交点即可得到答案

    #include<bits/stdc++.h>
    using namespace std;
    typedef double db;
    const db eps=1e-8,pi=acos(-1.0);
    inline int sig(const db&x){return fabs(x)<eps?0:(x<0?-1:1);}
    struct vec
    {
    	db x,y;
    	vec(db _x=0.0,db _y=0.0){x=_x,y=_y;}
    	inline void read(){scanf("%lf%lf",&x,&y);}
    	inline void print()const{printf("(%.6lf,%.6lf)",x,y);}
    	inline bool operator==(const vec&rhs)const{return sig(x-rhs.x)==0&&sig(y-rhs.y)==0;}
    	inline bool operator<(const vec&rhs)const{return sig(x-rhs.x)==0?sig(y-rhs.y)<0:sig(x-rhs.x)<0;}
    	inline vec operator+(const vec&rhs)const{return vec(x+rhs.x,y+rhs.y);}
    	inline vec operator-(const vec&rhs)const{return vec(x-rhs.x,y-rhs.y);}
    	inline vec operator*(const db&p)const{return vec(p*x,p*y);}
    	inline vec operator/(const db&p)const{return vec(x/p,y/p);}
    	inline db len()const{return sqrt(x*x+y*y);}
    	inline db ang()const{return atan2(y,x);}//向量极角
    };
    typedef vector<vec> vv;
    inline db dot(const vec&x,const vec&y){return x.x*y.x+x.y*y.y;}
    inline db cross(const vec&x,const vec&y){return x.x*y.y-x.y*y.x;}
    inline vec rot(const vec&p,const db&rad){return vec(p.x*cos(rad)-p.y*sin(rad),p.x*sin(rad)+p.y*cos(rad));}
    inline vec rot90(const vec&p){return vec(-p.y,p.x);}//求向量法向量
    inline db ang(const vec&p,const vec&q){return acos(dot(p,q)/(p.len())/(q.len()));}
    inline db todg(const db&x)
    {
    	db ans=x/pi*180;
    	while(sig(ans)<0)ans+=180;
    	while(sig(180-ans)<0)ans-=180;
    	return ans;
    }//弧度转度数
    struct cir
    {
    	vec o;db r;
    	inline void read(){o.read();scanf("%lf",&r);}
    	inline db ang(const vec&p)const{return atan2(p.y-o.y,p.x-o.x);}
    	inline vec pt(const db&rad)const{return vec(o.x+r*cos(rad),o.y+r*sin(rad));}//已知圆心角求点
    };
    inline db dis(const vec&P,const vec&Q){return (P-Q).len();}
    inline db dis(const vec&P,const vec&v,const vec&Q)
    {
    	return fabs(cross(Q-P,v)/v.len());
    }//点到直线距离
    inline vec pro(const vec&P,const vec&v,const vec&Q)
    {
    	db t=dot(Q-P,v)/v.len();
    	return P+v/v.len()*t;
    }//点在直线上的投影
    inline vec inr(const vec&P,const vec&v,const vec&Q,const vec&w)
    {
    	vec u=P-Q;
    	db t=cross(u,w)/cross(w,v);
    	return P+v*t;
    }
    inline int inr(const cir&c,const vec&P,const vec&v,vv&sol)
    {
    	db d=dis(P,v,c.o);
    	if(sig(d-c.r)>0)return 0;
    	else if(sig(d-c.r)==0)
    	{
    		sol.push_back(pro(P,v,c.o));
    		return 1;
    	}
    	vec mid=pro(P,v,c.o),e=v/v.len();
    	db l=sqrt(c.r*c.r-d*d);
    	sol.push_back(mid+e*l);
    	sol.push_back(mid-e*l);
    	return 2;
    }//圆和直线的交点:主要考虑垂径三角形
    inline int inr(const cir&a,const cir&b,vv&sol)
    {
    	db d=dis(a.o,b.o);
    	if(sig(d-a.r-b.r)>0)return 0;
    	else if(sig(d-a.r-b.r)==0)
    	{
    		sol.push_back(a.pt(a.ang(b.o)));
    		return 1;
    	}
    	db ag=a.ang(b.o),dl=acos((a.r*a.r+d*d-b.r*b.r)/(2*a.r*d));
    	sol.push_back(a.pt(ag+dl));
    	sol.push_back(a.pt(ag-dl));
    	return 2;
    }//圆和圆的交点
    inline int gtg(const cir&a,const vec&P,vector<db>&sol)
    {
    	db d=dis(a.o,P);
    	if(sig(a.r-d)>0)return 0;
    	else if(sig(a.r-d==0))
    	{
    		sol.push_back(todg(rot90(P-a.o).ang()));
    		return 1;
    	}
    	db dl=asin(a.r/d),ag=(a.o-P).ang();
    	sol.push_back(todg(ag-dl));
    	sol.push_back(todg(ag+dl));
    	return 2;
    }//求切线
    inline void print(vv&ans)
    {
    	putchar('[');
    	sort(ans.begin(),ans.end());int tot=ans.size();
    	for(int i=0;i<tot;++i)ans[i].print(),printf(i==tot-1?"":",");
    	putchar(']');puts("");
    }
    inline void print(vector<db>&ans)
    {
    	putchar('[');
    	sort(ans.begin(),ans.end());int tot=ans.size();
    	for(int i=0;i<tot;++i)printf("%.6lf",ans[i]),printf(i==tot-1?"":",");
    	putchar(']');puts("");
    }
    char ch[200];
    inline void solve1()
    {
    	vec A,B,C;A.read(),B.read(),C.read();
    	vec ans=inr((A+B)/2,rot90(B-A),(B+C)/2,rot90(B-C));
    	printf("(%.6lf,%.6lf,%.6lf)
    ",ans.x,ans.y,dis(ans,A));
    }
    inline void solve2()
    {
    	vec A,B,C;A.read(),B.read(),C.read();
    	vec c=B-A,b=C-A,a=C-B;
    	c=c/c.len(),a=a/a.len(),b=b/b.len();
    	vec ans=inr(A,b+c,C,a+b);
    	printf("(%.6lf,%.6lf,%.6lf)
    ",ans.x,ans.y,dis(A,B-A,ans));
    }
    inline void solve3()
    {
    	vector<db>sol;
    	cir c;vec t;c.read(),t.read();
    	gtg(c,t,sol);print(sol);
    }
    inline void solve4()
    {
    	vec P,A,B;db r;P.read(),A.read(),B.read();scanf("%lf",&r);
    	vec e=rot90(B-A)/dis(B,A);
    	vec C=A+e*r,D=A-e*r;vv sol;
    	cir c;c.o=P,c.r=r;
    	inr(c,C,B-A,sol);inr(c,D,B-A,sol);
    	print(sol);
    }
    inline void solve5()
    {
    	vec A,B,C,D;db r;
    	A.read(),B.read(),C.read(),D.read();scanf("%lf",&r);
    	vec e1=rot90(B-A)/dis(B,A),e2=rot90(D-C)/dis(D,C);
    	vec A1=A+e1*r,A2=A-e1*r,C1=C+e2*r,C2=C-e2*r;vv sol;
    	sol.push_back(inr(A1,B-A,C1,D-C));
    	sol.push_back(inr(A2,B-A,C1,D-C));
    	sol.push_back(inr(A1,B-A,C2,D-C));
    	sol.push_back(inr(A2,B-A,C2,D-C));print(sol);
    }
    inline void solve6()
    {
    	cir a,b;db r;a.read(),b.read();scanf("%lf",&r);
    	a.r+=r,b.r+=r;vv sol;
    	inr(a,b,sol);print(sol);
    }
    int main()
    {
    	while(scanf("%s",ch)!=EOF)
    	{
    		if(ch[0]=='I')solve2();
    		else if(ch[0]=='T')solve3();
    		else if(ch[4]=='u')solve1();
    		else if(ch[7]=='h')solve4();
    		else if(ch[18]=='L')solve5();
    		else solve6();
    	}
    	return 0;
    }
    

    UVA10652 Board Wrapping
    直接上凸包就可以了
    考虑(Andrew)算法,将所有点按照(x)从小到大排序,若相同则按照(y)从小到大排序
    从前往后扫,同时用栈记下当前在凸包中的点,如果新加入的点和之前的点形成凹进去的图形则弹栈(可以用叉积正负判断(右手定则))
    这样可以求出下图壳
    同理求出上图壳

    #include<bits/stdc++.h>
    using namespace std;
    typedef double db;
    const int N=2505;
    const db eps=1e-7,pi=acos(-1.0);
    inline int sig(const db&x){return fabs(x)<eps?0:(x<0?-1:1);}
    struct vec{db x,y;}p[N],q[N];
    inline bool operator<(const vec&x,const vec&y){return x.x<y.x||(x.x==y.x&&x.y<y.y);}
    inline bool operator==(const vec&x,const vec&y){return sig(x.x-y.x)==0&&sig(x.y-y.y)==0;}
    inline vec operator+(const vec&x,const vec&y){return {x.x+y.x,x.y+y.y};}
    inline vec operator-(const vec&x,const vec&y){return {x.x-y.x,x.y-y.y};}
    inline db cross(const vec&x,const vec&y){return x.x*y.y-x.y*y.x;}
    inline db torad(const db&x){return x/180*pi;} 
    inline vec rot(const vec&x,db rad)
    {
    	return {x.x*cos(rad)-x.y*sin(rad),x.x*sin(rad)+x.y*cos(rad)};
    }
    inline int Andrew(int n)
    {
    	sort(p+1,p+n+1);int m=0;
    	for(int i=1;i<=n;++i)
    	{
    		while(m>1&&sig(cross(q[m]-q[m-1],p[i]-q[m-1]))<=0)--m;
    		q[++m]=p[i];
    	}
    	int k=m;
    	for(int i=n-1;i;--i)
    	{
    		while(m>k&&sig(cross(q[m]-q[m-1],p[i]-q[m-1]))<=0)--m;
    		q[++m]=p[i];
    	}
    	m-=n>1;return m;
    }
    inline db S(int n)
    {
    	db ans=0.0;
    	for(int i=2;i<n;++i)
    		ans+=cross(q[i]-q[1],q[i+1]-q[1]);
    	ans/=2;
    	return fabs(ans);
    }//三角剖分求多边形面积
    int main()
    {
    	int T;scanf("%d",&T);
    	while(T--)
    	{
    		int n,tot=0;scanf("%d",&n);
    		db S1=0.0,S2=0.0;
    		for(int i=1;i<=n;++i)
    		{
    			db x,y,w,h,j;
    			scanf("%lf%lf%lf%lf%lf",&x,&y,&w,&h,&j);
    			j=-torad(j);vec o={x,y};
    			p[++tot]=o+rot({w/2,h/2},j);
    			p[++tot]=o+rot({w/2,-h/2},j);
    			p[++tot]=o+rot({-w/2,h/2},j);
    			p[++tot]=o+rot({-w/2,-h/2},j);
    			S1+=w*h;
    		}
    		S2=S(Andrew(tot));
    		printf("%.1lf %%
    ",S1*100/S2);
    	}
    	return 0;
    }
    
  • 相关阅读:
    【搜索】棋盘 luogu-3956
    【动态规划】石子合并 luogu-1880
    【动态规划】合唱队形 luogu-
    【模拟】报名签到 luogu-4445
    【排序+贪心】导弹拦截 luogu-1158
    【模拟】不高兴的津津
    【模拟】选数 luogu-1037
    「JOISC2020」建筑装饰 4
    「清华集训」小 Y 和恐怖的奴隶主
    「CF708E」Student's Camp
  • 原文地址:https://www.cnblogs.com/zmyzmy/p/14254630.html
Copyright © 2011-2022 走看看