计算几何模板

废话不多说,先附上一个粗糙的板吧 ,然后慢慢完善~

const double pi=acos(-1.0);
const double eps=1e-8;
/*my_template*/
/*Computational Geometry*/
const int N = 10010;
struct Point{
	double x,y;
	Point(double _x=0,double _y=0){
		x=_x,y=_y;
	}
	void read(){
		scanf("%lf%lf",&x,&y);
	}
}p[N];

struct Line{
	double a,b,c;//表示一条直线ax+by+c=0;
	Line(double _a,double _b,double _c):a(_a),b(_b),c(_c){}
	Line(){}
	void read(){
		scanf("%lf%lf%lf",&a,&b,&c);
	}
};
struct Lineseg{
	Point s,e;
	Lineseg(){}
	Lineseg(Point _s ,Point _e ){
		s = _s; e = _e;
	}
	void read(){
		s.read();e.read();
	}
};


class CG2d{
public:
	bool equal_double(double a,double b){
		return (fabs(a-b)<eps);
	}
	double dist_2(Point p1,Point p2){
		return ((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
	}
	double dist(Point p1,Point p2){
		return sqrt(dist_2(p1,p2));
	}
	bool equal_point(Point p1,Point p2){
		return equal_double(p1.x,p2.x)&&equal_double(p1.y,p2.y);
	}

	/*Cross product ;>0 ep在矢量opsp的逆时针方向 ;=0 共线*/
	double multiply(Point op,Point sp ,Point ep){
		return ((sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y));
	}
	/*Dot product ;r<0 夹角为锐角; =0 直角 ;>0 钝角*/
	double dotmultiply(Point op ,Point sp, Point ep){
		return ((sp.x - op.x)*(ep.x-op.x)+(sp.y-op.y)*(ep.y-op.y));
	}
	bool onlineseg(Lineseg l,Point p){
		return ((multiply(l.s,l.e,p)==0)&&( ((p.x-l.s.x)*(p.x-l.e.x)<=0) && ((p.y-l.s.y)*(p.y-l.e.y)<=0) ) );
	}
	/*返回点p以点o为圆心逆时针旋转alpha(单位:弧度)后所在的位置*/
	Point rotate(Point o ,double alpha,Point p){
		Point ret;
		p.x -= o.x;p.y -= o.y;
		ret.x = p.x*cos(alpha) - p.y*sin(alpha) + o.x;
		ret.y = p.y*cos(alpha) + p.x*sin(alpha) + o.y;
		return ret;
	}
	/*angle计算夹角*/
	double angle(Point op,Point sp,Point ep){
		double cosfi,phi,norm;
		double dsx = sp.x - op.x,dsy = sp.y - op.y;
		double dex = ep.x - op.x,dey = ep.y - op.y;
		cosfi = dsx*dex + dsy * dey;
		norm = (dsx*dsx+dsy*dsy)*(dex*dex+dey*dey);
		cosfi /= sqrt(norm);
		if (cosfi >= 1.0) return 0;
		if (cosfi <= -1.0) return -pi;
		phi = acos(cosfi);
		if (dsx*dey-dsy*dex>0) return phi;
		return -phi;
	}
	/*******************线段与直线的基本运算***************/
	/*判断点与线段的关系,用途很广泛*/  
	double relation(Point p,Lineseg l){
		return dotmultiply(l.s,p,l.e)/dist_2(l.s,l.e);
	}

	/*垂足点p到线段l的垂足*/
	Point perpendicular(Point p,Lineseg l){
		double r = relation(p,l);
		Point tp(l.s.x + r * (l.e.x - l.s.x),l.s.y + r * (l.e.y - l.s.y));
		return tp;
	}

	/*求点P到线段l的最短距离,并返回线段上距该点最近的点np*/
	double ptolinesegdist(Point p,Lineseg l,Point &np){
		double r = relation(p,l);
		if (r<0) np = l.s;
		else if (r>1) np = l.e ;
		else np = perpendicular(p,l);
		return dist(p,np);
	}
	/*求点p到线段l所在直线的距离*/
	double ptolinedist(Point p,Lineseg l){
		return fabs(multiply(l.s,l.e,p))/dist(l.s,l.e);
	}
	/*求点到折线集的最近距离,并返回最近点*/
	double ptopointset(int vcnt,Point pointset[],Point p,Point &q){
		double rd = 1000000000.0,td;   //rd初始化 赋值成一个很大的值
		Lineseg l;
		Point rq,tq;
		for(int i = 0;i < vcnt-1; ++i){
			l.s = pointset[i];l.e = pointset[i+1];
			td = ptolinesegdist(p,l,tq);
			if (td < rd) rd = td,rq = tq;
		}
		q = rq;
		return rd; 
	}
	double ptopolygon(int vcnt,Point pointset[],Point p,Point &q){
		Point tq;
		double d = ptopointset(vcnt,pointset,p,q);
		double td = ptolinesegdist(p,Lineseg(pointset[vcnt-1],pointset[0]),tq);
		if (td < d) {
			q = tq;
			return td;
		}
		return d;
	}
	/*判断圆是否在多边形内 这里木有判断圆心是否在多边形内,默认在里面*/
	bool CircleInsidePolygon(int vcnt,Point polygon[],Point center,double radius){
		Point q;
		double d = ptopolygon(vcnt,polygon,center,q);
		if (radius <= d || fabs(d-radius) < eps) return 1;
		return 0;
	}
	/*返回 两个矢量l1和l2的夹角的余弦 (-1..1) 注意如果要求余弦的话,反余弦函数的定义是从0到pi的*/
	double cosine(Lineseg l1,Lineseg l2){
		return ((l1.e.x-l1.s.x) * (l2.e.x - l2.s.x) + (l1.e.y - l1.s.y) * (l2.e.y - l2.s.y))
			/(dist(l1.s,l1.e)*dist(l2.s,l2.e));
	}
	/*返回线段l1 与 l2之间的夹角, 单位为弧度 范围(-pi,pi)*/
	double lsangle(Lineseg l1,Lineseg l2){
		Point o(0,0),s,e;
		s.x = l1.e.x - l1.s.x;
		s.y = l1.e.y - l1.s.y;

		e.x = l2.e.x - l2.s.x;
		e.y = l2.e.y - l2.s.y;
		return angle(o,s,e);
	}
	/*如果线段u和v 相交(包括相交在端点处)时,然后true*/
	bool Isintersect(Point a1, Point a2, Point b1, Point b2) {
		//判断两条线段是否相交     
		return  min(a1.x, a2.x) <= max(b1.x, b2.x)&&         
			min(a1.y, a2.y) <= max(b1.y, b2.y) &&         
			min(b1.x, b2.x) <= max(a1.x, a2.x) &&         
			min(b1.y, b2.y) <= max(a1.y, a2.y) &&         
			multiply(a1, a2, b1) * multiply(a1, a2, b2) <= 0 &&         
			multiply(b1, b2, a1) * multiply(b1, b2, a2) <= 0 ;        
	}
	/*如果线段u和v 相交(不包括相交在端点处)时,然后true*/
	bool IsintersectNotOnline(Point a1, Point a2, Point b1, Point b2){
		return Isintersect(a1,a2,b1,b2) && (!onlineseg(Lineseg(b1,b2),a1)) &&
			(!onlineseg(Lineseg(b1,b2),a2)) && (!onlineseg(Lineseg(a1,a2),b1)) &&
			(!onlineseg(Lineseg(a1,a2),b2));
	}
	/*直线与线段相交模板:点(P1,P2)是否与过点(Q1,Q2)的直线相交 没有判规范 */
	bool intersect_line_seg(Point P1,Point P2,Point Q1,Point Q2) {   
		return multiply(Q1,P1,Q2)*multiply(Q1,Q2,P2)>=0;
	} 
	//已知直线过的两点 求过这两点的直线方程 ax+by+c=0; a>=0;
	Line makeline(Point p1,Point p2){
		Line tl;
		tl.a = p2.y - p1.y;
		tl.b = p1.x - p2.x;
		tl.c = p1.y * p2.x - p1.x * p2.y;
		//if (tl.a<0) tl.a = -tl.a,tl.b=-tl.b,tl.c=-tl.c;
		return tl;
	}
	//计算直线的倾斜角
	double slope(Line l){
		if (fabs(l.a) < eps) return 0.0;
		if (fabs(l.b) < eps) return 1e20;  //斜率无穷大
		return -(l.a/l.b);
	}
	//返回直线的倾斜角
	double alpha(Line l){
		if (fabs(l.a)<eps) return 0.0;
		if (fabs(l.b)<eps) return pi/2;
		double k = slope(l);
		if (k>0) return atan(k);
		return pi+atan(k);
	}
	//求点p关于直线l 的对称点
	Point symmetry(Line l ,Point p){
		Point rp;
		rp.x = ((l.b*l.b-l.a*l.a) * p.x - 2*l.a*l.b*p.y - 2*l.a*l.c)/(l.a*l.a+l.b*l.b);
		rp.y = ((l.a*l.a-l.b*l.b) * p.y - 2*l.a*l.b*p.x - 2*l.b*l.c)/(l.a*l.a+l.b*l.b);
		return rp;
	}
	/*如果两条直线l1 和 l2 相交返回true 和交点p*/
	bool lineintersect(Line l1,Line l2,Point &p){
		double d = l1.a * l2.b - l2.a*l1.b;
		if (fabs(d)<eps) return 0;
		p.y = (l1.c * l2.a - l1.a * l2.c)/d;
		p.x = (l2.c * l1.b - l1.c * l2.b)/d;
		return 1;
	}
	//判断直线重合
	bool Line_Coincide(const Line &l1,const Line &l2){
		return equal_double(l1.a*l2.c,l2.a*l1.c) && equal_double(l1.b*l2.c,l2.b*l1.c);
	}
	/*判断点是否在多边形内 如果点在多边形上也视为在里面*/
	bool point_in_polygon(int vcnt,Point pointset[],Point p){
		int cnt = 0;
		Lineseg l(p,Point(1e10,p.y));
		Point pn = pointset[vcnt];
		pointset[vcnt] = pointset[0];
		fr(i,0,vcnt){
			if (onlineseg(Lineseg(pointset[i],pointset[i+1]),p)) return 1;
			if (equal_double(pointset[i].y ,pointset[i+1].y)) continue;
			int tmp = -1;
			if (onlineseg(l,pointset[i])) tmp=i;
			else if (onlineseg(l,pointset[i+1])) tmp =i+1;
			if (tmp != -1 && equal_double(pointset[tmp].y,min(pointset[i].y,pointset[i+1].y))) cnt++;
			if (tmp == -1 && Isintersect(l.s,l.e,pointset[i],pointset[i+1])) cnt++;
		}
		pointset[vcnt] = pn;
		if (cnt&1) return 1;
		return 0;
	}
	//已知三角形三个顶点的坐标,求三角形的面积     
	double triangleArea(Point p0, Point p1, Point p2) {  
		double k = p0.x * p1.y + p1.x * p2.y   + p2.x * p0.y 
			- p1.x * p0.y - p2.x * p1.y - p0.x * p2.y;     
		return fabs(k/2);
	}  
	//凸包的极角序
	/*static bool gramhap_cmp(Point a,Point b){
		double k = cg2d.multiply(p[0],a,b);
		if (fabs(k)<eps) return cg2d.dist(a,p[0])<cg2d.dist(p[0],b);
		else if (k>0) return 1;
		else return 0;
	}
	//n为原来多边形的点的个数 返回凸包上的点的个数
	int graham(int n,Point chs[]){
		int mny = p[0].y ,idx = 0;
		fr(i,1,n){
			if (p[i].y < mny) mny = p[i].y,idx = i;
			else if (p[i].y == mny &&p[i].x <p[idx].x) idx = i;
		}
		Point tmp = p[idx];
		p[idx] = p[0];p[0] = tmp;
		sort(p+1,p+n,gramhap_cmp);
		chs[0] = p[n-1];chs[1] = p[0];
		int stop = 1,pos =1;
		while(pos<=n-1){
			double d = multiply(chs[stop],chs[stop-1],p[pos]);
			if (d<=0) chs[++stop] = p[pos++];
			else stop--;
		}
		return stop+1;
	}
	//计算凸包的周长
	double convex_circumference(int n,Point p[]){
		double ret = 0;
		fr(i,0,n-1) ret += dist(p[i],p[i+1]);
		ret += dist(p[n-1],p[0]);
		return ret;
	}
	double convex_area(int n,Point chs[]){
		double ret = 0;Point s = chs[0];
		fr(i , 1,n-1)  ret += multiply(s,chs[i],chs[i+1]);
		return fabs(ret)/2;
	}*/
}cg2d;




利用这个板 可以轻松的切掉一般的计算几何题目

poj 1066 Treasure Hunt

枚举所有先线段的短点,与目标点判一次相交即可

#define sfint(x) scanf("%d",&x)
#define sfint2(x,y) scanf("%d%d",&x,&y)
#define sfint3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define sfstr(c) scanf("%s",c)
#define pfint(x) printf("%d\n",x)
#define fr(i,s,n) for(int i=s;i<n;++i)
#define _fr(i,n,s) for(int i=n-1;i>=s;--i)
#define cl(a) memset(a,0,sizeof(a))
Lineseg l[31];
Point st;
int n;
int main(){
	fi;
	sfint(n);
	fr(i,0,n) l[i].read();
	st.read();
	int ans = 100;
	fr(i,0,n){
		int tmp = 0;
		fr(j,0,n) if (cg2d.Isintersect(st,l[i].s,l[j].s,l[j].e)) tmp++;
		ans =min(tmp,ans);tmp = 0;
		fr(j,0,n) if (cg2d.Isintersect(st,l[i].e,l[j].s,l[j].e)) tmp++;
		ans =min(tmp,ans);
	}
	if (n == 0) ans = 1;
	printf("Number of doors = %d\n",ans);
}



poj 2653 Pick-up sticks

struct S{
	Lineseg l;
	int pos;
}l[100010];

list<S> lis;
int n;
void solve(){
	lis.clear();
	list<S>::iterator lit,tmpit;;
	lis.insert(lis.begin(),l[1]);

	fr(i ,2,n+1){
		for(lit = lis.begin();lit!=lis.end();){
			tmpit = lit;
			++lit;
			if(cg2d.Isintersect(tmpit->l.s,tmpit->l.e,l[i].l.s,l[i].l.e)){
				lis.erase(tmpit);
			}
		}
		lis.push_back(l[i]);
	}
	printf("Top sticks: ");
	for (lit = lis.begin();lit!=lis.end();){
		printf("%d",lit->pos);
		++lit;
		if (lit == lis.end()){
			printf(".\n");
		}else{
			printf(", ");
		}
	}
}
void inp(){
	fr(i,1,n+1) l[i].l.read(),l[i].pos = i;
}
int main(){
#ifdef local
	fi;
#endif
	while(sfint(n),n){
		inp();
		solve();
	}

poj1410 Intersection

Point rec[4];
int main(){
#ifdef local
	fi;
#endif
	int t;
	Lineseg l;
	Point p,q;
	sfint(t);
	while(t--){
		l.read();
		rec[0].read();rec[2].read();
		double lx = min(rec[0].x,rec[2].x),hx = max(rec[0].x,rec[2].x);
		double ly = min(rec[0].y,rec[2].y),hy = max(rec[0].y,rec[2].y);
		rec[1].x = rec[0].x;rec[1].y = rec[2].y;
		rec[3].x = rec[2].x;rec[3].y = rec[0].y;
		bool flag = 0;
		if((l.s.x <= hx && l.s.x>= lx && l.s.y <= hy && l.s.y >= ly) &&
			(l.e.x <= hx && l.e.x>= lx && l.e.y <= hy && l.e.y >= ly) )
			flag = 1;
		if (!flag)
		fr(i,0,4){
			if (cg2d.Isintersect(rec[i],rec[(i+1)%4],l.s,l.e)){
				flag = 1;
				break;
			}
		}
		if (flag) puts("T");else puts("F");
	}
	return 0;
}


POJ 1584 A Round Peg in a Ground Hole

Point center,p[100000],chs[100000];;
int n;
double r;
bool check(){
	int stop =1,pos = 1;
	chs[0] = p[n-1],chs[1] = p[0];chs[n] = p[0];p[n] = p[0];
	bool flag = 0;
	while(pos<=n){
		double d = cg2d.multiply(chs[stop],chs[stop-1],p[pos]);
		if ((d<=0)) {
			chs[++stop] = p[pos++];
		}else {
			flag = 1;break;
		}
	}
	if (flag == 1){
		pos = 1;stop =1;
		while(pos<=n){
			double d = cg2d.multiply(chs[stop],chs[stop-1],p[pos]);
			if (d>=0) {
				chs[++stop] = p[pos++];
			}else return 0;
		}
	}
	return 1;
}
int main(){
	fi;
	while(1){
		sfint(n);
		if (n<3) break;
		sfdl(r);
		center.read();
		fr(i,0,n) p[i].read();
		if (check()){
			if (cg2d.point_in_polygon(n,p,center)){
				if (cg2d.CircleInsidePolygon(n,p,center,r)) puts("PEG WILL FIT");
				else puts("PEG WILL NOT FIT");
			}else puts("PEG WILL NOT FIT");
		}else{
			puts("HOLE IS ILL-FORMED");
		}
	}
}


POJ 1113 Wall


Point chs[N],p[N];
int main(){
	int n;
	double l;
	sfint(n);sfdl(l);
	fr(i , 0,n){
		p[i].read();
	}
	int vcnt = cg2d.graham(n,chs);
	double ans = cg2d.convex_circumference(vcnt,chs);
	ans += pi*2*l;
	printf("%.0f\n",ans);
}


POJ 1228 Grandpa's Estate

Point chs[N];

int n;
void solve(){
	int vcnt = cg2d.graham(n,chs);
	bool flag = 1;
	Point prepre=chs[1],pre=chs[2];
	chs[vcnt] = chs[0];
	int ct = 2;
	fr(i , 3,vcnt+1){  //最后一个还要和起点检查一下下;
		if (ct == 2){
			if (!(fabs(cg2d.multiply(prepre,pre,chs[i]))<eps)) {
				flag = 0 ; break;
			}
			else {ct++;prepre = pre;pre=chs[i];}
		}else{
			if (fabs(cg2d.multiply(prepre,pre,chs[i]))<eps) ct++;
			else ct = 2;
			prepre = pre;pre = chs[i];
		}
	}
	if (!flag) puts("NO");
	else{
		if (fabs(cg2d.multiply(prepre,pre,chs[1]))<eps) 
		puts("YES");
		else puts("NO");
	}
}
int main(){
	int t;
	sfint(t);
	while(t--){
		sfint(n);
		fr(i , 0,n) p[i].read();
		if (n<6) puts("NO");
		else solve();
	}
	return 0;
}


POJ 3608 Bridge Across Islands

int n,m,cntp ,cntq;
Point  chsp[N];
Point chsq[N];
double solve(Point p[],Point q[]){
	int sp=0,sq=0;
	fr(i , 1,cntp)  
		if ((p[i].y<p[sp].y)||(cg2d.equal_double(p[i].y,p[sp].y)&&p[i].x<p[sp].x))
			sp = i;
	fr(i , 1,cntq)
		if ((q[i].y>q[sq].y)||(cg2d.equal_double(q[i].y,q[sq].y)&&q[i].x>q[sq].x))
			sq = i;
	int tp = sp,tq = sq;
	double ans = cg2d.dist(p[sp],q[sq]);
	Point xxx;
	do{
		double k = cg2d.multiply(Point(0,0),Point(p[(sp+1)%cntp].x-p[sp].x,p[(sp+1)%cntp].y-p[sp].y),
			Point(q[(sq+1)%cntq].x-q[sq].x,q[(sq+1)%cntq].y-q[sq].y));
		if (cg2d.equal_double(k,0)){
			ans = min(ans,cg2d.ptolinesegdist(p[sp],Lineseg(q[sq],q[(sq+1)%cntq]),xxx));
			ans = min(ans,cg2d.ptolinesegdist(p[(sp+1)%cntp],Lineseg(q[sq],q[(sq+1)%cntq]),xxx));
			ans = min(ans,cg2d.ptolinesegdist(q[sq],Lineseg(p[sp],p[(sp+1)%cntp]),xxx));
			ans = min(ans,cg2d.ptolinesegdist(q[(sq+1)%cntq],Lineseg(p[sp],p[(sp+1)%cntp]),xxx));
			sp = (sp+1)%cntp;sq = (sq+1)%cntq;
		}
		else if (k<0){
			ans = min(ans,cg2d.ptolinesegdist(q[sq],Lineseg(p[sp],p[(sp+1)%cntp]),xxx));
			sp = (sp+1)%cntp;
		}else{
			ans = min(ans,cg2d.ptolinesegdist(p[sp],Lineseg(q[sq],q[(sq+1)%cntq]),xxx));
			sq = (sq+1)%cntq;
		}
	}while(!(tp == sp&&tq == sq));
	return ans;
}
int main(){
	
	while(1){
		sfint2(n,m);
		if (n==0 && m==0) break;
		fr(i, 0,n) p[i].read();
		fr(i,0,m) q[i].read();
		cntp = cg2d.graham(n,p,chsp);//求最远点对时graham:pos<n-1
		cntq = cg2d.graham(m,q,chsq);
		printf("%.5f\n",solve(chsp,chsq));
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值