计算几何基础

计算几何基础

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;
}
原文地址:https://www.cnblogs.com/zmyzmy/p/14254630.html