计算几何入门

模板,主要是参照浙大的模板和黑书。

做了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

注意恶心的精度。。。

View Code
#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;

}

POJ 1385 Lifting the Stone

裸模板 求多边形重心。

求多边形重心的原理,划分成多个三角形,先求出每个三角形的重心,以面积作为权值,详细解释还是看黑书把。

View Code
#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;

}

POJ 1408 Fishnet

本来是挺简单的一个题目的,我eps选的1e-8,最后结果都+eps了,然后一直疯狂WA,太郁闷了,eps不能乱加,加上或许就影响最后结果了,不加,看看是否存在-0的情况。合理选取eps。

View Code
#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;

}

POJ 1039 Pipe

黑书上的例题,根据几个讲解,然后套几个模板,然后 看清楚题意。。这是求最后的x坐标,我看错题了啊。。。

View Code
#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;

}

 

 

你可能感兴趣的:(入门)