模板,主要是参照浙大的模板和黑书。
做了POJ计划上计算几何初级上的题,成功的迈出了计算几何第一步!
常用结构体和宏定义
#define eps 1e-8 #define PI 3.141592653 #define _sign(x) ((x) > eps?1:((x) < -eps ? 2 :0)) //sign(x)是用来控制精度的浙大和黑书上关于这个函数写法不一样。正返回1负返回2,接近正负eps返回0 #define zero(x) (((x) > 0 ? (x):(-x)) < eps) //接近0返回0,其他返回绝对值 struct Point { double x,y; }; struct line { Point a,b; }; double dblcmp(double a)//黑书上控制精度写法,返回1和-1 { if(fabs(a) < eps) return 0; return a > 0? 1:-1; }
叉积 很多种写法,意思都一样。
double xmult(point a,point b,point c)//浙大模板上用xmult这个名字。。。ac与bc叉积 { return (a.x-c.x)*(b.y-c.y) - (b.x-c.x)*(a.y-c.y); } double det(double x1,double y1,double x2,double y2)//叉积 { return x1*y2 - y1*x2; } double cross(Point a,Point b,Point c)//叉积(黑书上的写法) { return det(a.x-c.x,a.y-c.y,b.x-c.x,b.y-c.y); }
各种函数
double dis(Point a,Point b)//两点距离 { return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y)); } int is_convex(int n)//允许存在共线,判断是不是凸包(浙大模板) { int i,s[3] = {1,1,1}; double t; for(i = 0; i < n&&s[1]|s[2]; i ++) { t = cross(p[(i+1)%n],p[(i+2)%n],p[i]); s[_sign(t)] = 0; } return s[1]|s[2]; } int inside_convex(Point q,int n)//判断q点是否在凸多边形内部或者边上(浙大模板) { int i,s[3] = {1,1,1}; double t; for(i = 0;i < n&&s[1]|s[2];i ++) { t = cross(p[(i+1)%n],q,p[i]); s[_sign(t)] = 0; } return s[1]|s[2]; } double disptoline(Point q,line l)//点到直线距离(浙大模板) { return fabs(cross(q,l.a,l.b))/dis(l.a,l.b); } Point barycenter(Point a,Point b,Point c)//浙大模板上这个函数是中线相交写的,那样掉精度很厉害 { Point ret; ret.x = (a.x + b.x + c.x)/3; ret.y = (a.y + b.y + c.y)/3; return ret; } Point barycenter(int n)//多边形求重心,原理参见黑书 { Point ret,t; double t1 = 0,t2; int i; ret.x = 0; ret.y = 0; for(i = 1;i < n-1;i ++) { if(fabs(t2 = xmult(p[0],p[i],p[i+1])) > eps) { t = barycenter(p[0],p[i],p[i+1]); ret.x += (t.x*t2); ret.y += (t.y*t2); t1 += t2; } } if(fabs(t1) > eps) { ret.x /= t1; ret.y /= t1; } return ret; } point intersection(line u,line v)//求两条直线的交点(浙大模板) { point ret = u.a; double t = ((u.a.x-v.a.x)*(v.a.y-v.b.y) - (u.a.y-v.a.y)*(v.a.x-v.b.x)) /((u.a.x-u.b.x)*(v.a.y-v.b.y) - (u.a.y-u.b.y)*(v.a.x-v.b.x)); ret.x += (u.b.x - u.a.x)*t; ret.y += (u.b.y - u.a.y)*t; return ret; } double area_polygon(int n,point *p)//多边形的面积(浙大模板) { double s1,s2; s1 = s2 = 0; int i; for(i = 0;i < n;i ++) { s1 += p[(i+1)%n].y*p[i].x; s2 += p[(i+1)%n].x*p[i].y; } return fabs(s1-s2)/2; } int dot_online(point p,line l)//判断p点,在线段l上(浙大模板) { return zero(xmult(p,l.a,l.b))&&(l.a.x-p.x)*(l.b.x-p.x)<eps&&(l.a.y-p.y)*(l.b.y-p.y)<eps;
//原理 叉积为0,且x,y坐标在a和b点之间。 }
POJ 1584 A Round Peg in a Ground Hole
注意恶心的精度。。。
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define LL __int64 #define N 100001 #define eps 1e-8 #define PI 3.141592653 #define _sign(x) ((x) > eps?1:((x) < -eps ? 2 :0)) struct Point { double x,y; } p[N]; struct line { Point a,b; }; double Abs(double a) { return a > 0 ? a:-a; } double det(double x1,double y1,double x2,double y2) { return x1*y2 - y1*x2; } double cross(Point a,Point b,Point c) { return det(a.x-c.x,a.y-c.y,b.x-c.x,b.y-c.y); } double dis(Point a,Point b)//两点距离 { return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y)); } int is_convex(int n)//允许存在共线 { int i,s[3] = {1,1,1}; double t; for(i = 0; i < n&&s[1]|s[2]; i ++) { t = cross(p[(i+1)%n],p[(i+2)%n],p[i]); s[_sign(t)] = 0; } return s[1]|s[2]; } int inside_convex(Point q,int n)//判断q点是否在凸多边形内部或者边上 { int i,s[3] = {1,1,1}; double t; for(i = 0;i < n&&s[1]|s[2];i ++) { t = cross(p[(i+1)%n],q,p[i]); s[_sign(t)] = 0; } return s[1]|s[2]; } double disptoline(Point q,line l)//点到直线距离 { return Abs(cross(q,l.a,l.b))/dis(l.a,l.b); } int main() { double r; int n,i; Point temp; line ln; while(scanf("%d",&n)!=EOF) { if(n < 3) break; scanf("%lf%lf%lf",&r,&temp.x,&temp.y); for(i = 0; i < n; i ++) scanf("%lf%lf",&p[i].x,&p[i].y); if(!is_convex(n)) { printf("HOLE IS ILL-FORMED\n"); continue; } if(inside_convex(temp,n)) { for(i = 0;i < n;i ++) { ln.a = p[i]; ln.b = p[(i+1)%n]; if(_sign(r-disptoline(temp,ln)) == 1) break; } if(i == n) printf("PEG WILL FIT\n"); else printf("PEG WILL NOT FIT\n"); } else printf("PEG WILL NOT FIT\n"); } return 0; }
裸模板 求多边形重心。
求多边形重心的原理,划分成多个三角形,先求出每个三角形的重心,以面积作为权值,详细解释还是看黑书把。
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define eps 1e-8 #define N 1000001 struct Point { double x,y; }p[N]; struct line { Point a,b; }; double xmult(Point a,Point b,Point c) { return (a.x-c.x)*(b.y-c.y) - (b.x-c.x)*(a.y-c.y); } Point barycenter(Point a,Point b,Point c) { Point ret; ret.x = (a.x + b.x + c.x)/3; ret.y = (a.y + b.y + c.y)/3; return ret; } Point barycenter(int n) { Point ret,t; double t1 = 0,t2; int i; ret.x = 0; ret.y = 0; for(i = 1;i < n-1;i ++) { if(fabs(t2 = xmult(p[0],p[i],p[i+1])) > eps) { t = barycenter(p[0],p[i],p[i+1]); ret.x += (t.x*t2); ret.y += (t.y*t2); t1 += t2; } } if(fabs(t1) > eps) { ret.x /= t1; ret.y /= t1; } return ret; } int main() { int n,t,i; Point ans; scanf("%d",&t); while(t--) { scanf("%d",&n); for(i = 0;i < n;i ++) { scanf("%lf%lf",&p[i].x,&p[i].y); } ans = barycenter(n); printf("%.2lf %.2lf\n",ans.x+eps,ans.y+eps); } return 0; }
本来是挺简单的一个题目的,我eps选的1e-8,最后结果都+eps了,然后一直疯狂WA,太郁闷了,eps不能乱加,加上或许就影响最后结果了,不加,看看是否存在-0的情况。合理选取eps。
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define eps 1e-8 struct point { double x,y; }; struct line { point a,b; }; point intersection(line u,line v) { point ret = u.a; double t = ((u.a.x-v.a.x)*(v.a.y-v.b.y) - (u.a.y-v.a.y)*(v.a.x-v.b.x)) /((u.a.x-u.b.x)*(v.a.y-v.b.y) - (u.a.y-u.b.y)*(v.a.x-v.b.x)); ret.x += (u.b.x - u.a.x)*t; ret.y += (u.b.y - u.a.y)*t; return ret; } double area_polygon(int n,point *p) { double s1,s2; s1 = s2 = 0; int i; for(i = 0;i < n;i ++) { s1 += p[(i+1)%n].y*p[i].x; s2 += p[(i+1)%n].x*p[i].y; } return fabs(s1-s2)/2; } int main() { int i,j,n; double ans; line u[51],v[51]; point p[4]; while(scanf("%d",&n)!=EOF) { if(!n) break; ans = 0; u[0].a.x = 0; u[0].a.y = 0; u[0].b.x = 0; u[0].b.y = 1; for(i = 1;i <= n;i ++) { scanf("%lf",&u[i].a.x); u[i].a.y = 0; } u[n+1].a.x = 1; u[n+1].a.y = 0; u[n+1].b.x = 1; u[n+1].b.y = 1; for(i = 1;i <= n;i ++) { scanf("%lf",&u[i].b.x); u[i].b.y = 1; } v[0].a.x = 0; v[0].a.y = 0; v[0].b.x = 1; v[0].b.y = 0; for(i = 1;i <= n;i ++) { scanf("%lf",&v[i].a.y); v[i].a.x = 0; } v[n+1].a.x = 0; v[n+1].a.y = 1; v[n+1].b.x = 1; v[n+1].b.y = 1; for(i = 1;i <= n;i ++) { scanf("%lf",&v[i].b.y); v[i].b.x = 1; } for(i = 0;i <= n;i ++) { for(j = 0;j <= n;j ++) { p[0] = intersection(u[i],v[j]); p[1] = intersection(u[i],v[j+1]); p[2] = intersection(u[i+1],v[j+1]); p[3] = intersection(u[i+1],v[j]); if(ans < area_polygon(4,p)) ans = area_polygon(4,p); } } printf("%.6lf\n",ans); } return 0; }
黑书上的例题,根据几个讲解,然后套几个模板,然后 看清楚题意。。这是求最后的x坐标,我看错题了啊。。。
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define zero(x) (((x) > 0 ? (x):(-x)) < eps) #define eps 1e-8 #define N 21 struct point { double x,y; } p1[N],p2[N]; struct line { point a,b; }; double xmult(point a,point b,point c) { return (a.x-c.x)*(b.y-c.y) - (b.x-c.x)*(a.y-c.y); } point intersection(line u,line v) { point ret = u.a; double t = ((u.a.x-v.a.x)*(v.a.y-v.b.y)-(u.a.y-v.a.y)*(v.a.x-v.b.x)) /((u.a.x-u.b.x)*(v.a.y-v.b.y)-(u.a.y-u.b.y)*(v.a.x-v.b.x)); ret.x += (u.b.x-u.a.x)*t; ret.y += (u.b.y-u.a.y)*t; return ret; } int dot_online(point p,line l) { return zero(xmult(p,l.a,l.b))&&(l.a.x-p.x)*(l.b.x-p.x)<eps&&(l.a.y-p.y)*(l.b.y-p.y)<eps; } double dblcmp(double a) { if(fabs(a) < eps) return 0; return a > 0? 1:-1; } int main() { int i,j,k,n,z; double ans,t; line u,v; point temp,str; while(scanf("%d",&n)!=EOF) { if(!n) break; for(i = 0; i < n; i ++) { scanf("%lf%lf",&p1[i].x,&p1[i].y); p2[i].x = p1[i].x; p2[i].y = p1[i].y - 1; } z = 1; ans = -100000000; for(i = 0; i < n&&z; i ++) { for(j = 0; j < n&&z; j ++) { if(i != j) { u.a = p1[i]; u.b = p2[j]; v.a = p1[0]; v.b = p2[0]; k = 0; str = intersection(u,v); if(dot_online(str,v)) { for(k = 1; k < n; k ++) { v.a = p1[k]; v.b = p2[k]; temp = intersection(u,v); if(!dot_online(temp,v)) { v.a = p1[k];//上 v.b = p1[k-1]; temp = intersection(u,v); if(dot_online(temp,v)) { t = temp.x; if(dblcmp(t-ans) == 1) ans = t; } v.a = p2[k]; v.b = p2[k-1]; temp = intersection(u,v); if(dot_online(temp,v)) { t = temp.x; if(dblcmp(t-ans) == 1) ans = t; } break; } } } if(k == n) { z = 0; } } } } if(z) printf("%.2lf\n",ans+eps); else printf("Through all the pipe.\n"); } return 0; }