计算几何入门

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

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

 

 

posted @ 2013-02-12 15:46  Naix_x  阅读(341)  评论(0编辑  收藏  举报