计算几何初步

嗯因为本人就是个计算几何渣所以标题就写个初步好了…

①求多边形面积 poj3907

随便找一个点,对多边形相邻顶点求叉积。加在一起求绝对值即可。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <math.h>
#include <limits>
#include <set>
#include <map>
using namespace std;
int n;
double x[2333333],y[2333333];
int main()
{
    while(scanf("%d",&n),n)
    {
        for(int i=0;i<n;i++) scanf("%lf%lf",x+i,y+i);
        double mx=2000000000,my=2000000000;
        for(int i=0;i<n;i++) mx=min(mx,x[i]), my=min(my,y[i]);
        --mx; --my;
        double ans=0;
        for(int i=0;i<n;i++)
        {
            double x1=x[i]-mx, y1=y[i]-my;
            double x2=x[(i+1)%n]-mx, y2=y[(i+1)%n]-my;
            ans+=x1*y2-y1*x2;
        }
        ans/=2;
        if(ans<0) ans=-ans;
        printf("%.0lf
",ans);
    }
}

②点是否在多边形内 zoj1081

经典问题了,只要把这个点水平地做一条射线,然后统计经过多边形边的交点数。

image

经过一番严谨的推导(需要的自行百度),我们发现只要判一下和多边形交点的奇偶性就可以了。

听起来很简单…我连着WA了大概二十几发

边界:

imageimageimage

在多边形边界上要特判

要忽略水平边

交点正好是多边形端点时判断另一个段点的上下(就是多边形的边在直线上面还是下面分别算0个或者1个交点,这样交在顶点上算两次就都是偶数)

写起来各种蛋疼,而且这题多组数据还有PE…醉了

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <math.h>
#include <limits>
#include <set>
#include <map>
using namespace std;
typedef double ld;
typedef pair<ld,ld> pnt;
#define x first
#define y second
struct cl
{
    ld a,b,c;
    cl() {a=b=c=0;}
    cl(ld A,ld B,ld C) {a=A;b=B;c=C;}
};
int n,m;
pnt as[233333];
ld eps=1e-6;
cl gl(pnt a,pnt b)
{
    return cl(a.y-b.y,b.x-a.x,a.x*b.y-a.y*b.x);
}
bool zero(ld s) {return fabs(s)<eps;}
bool oncl(cl a,pnt b)
{
    return zero(a.a*b.x+a.b*b.y+a.c);
}
bool onseg(pnt a,pnt b,pnt c)
{
    if(!oncl(gl(a,b),c)) return 0;
    if(min(a.x,b.x)-eps<=c.x&&c.x<=max(a.x,b.x)+eps);else return 0;
    if(min(a.y,b.y)-eps<=c.y&&c.y<=max(a.y,b.y)+eps);else return 0;
    return 1;
}
bool same(pnt a,pnt b)
{
    return zero(a.x-b.x)&&zero(a.y-b.y);
}
bool chk(pnt s)
{
    //在多边形边上
    for(int i=0;i<n;i++)
    {
        if(onseg(as[i],as[(i+1)%n],s)||same(as[i],s)) return 1;
    }
    int cnt=0;
    for(int i=0;i<n;i++)
    {
        //水平线不考虑 
        if(zero(as[i].y-as[(i+1)%n].y)) continue;
        cl cll=gl(as[i],as[(i+1)%n]);
        ld xx=(-cll.b*s.y-cll.c)/cll.a,yy=s.y; //交点
        if(!onseg(as[i],as[(i+1)%n],pnt(xx,yy))||xx<s.x) continue;
        if(same(pnt(xx,yy),as[i])||same(pnt(xx,yy),as[(i+1)%n]))
        {
            if(same(pnt(xx,yy),as[i])) cnt+=as[(i+1)%n].y>yy;
            else cnt+=as[i%n].y>yy;
        }
        else cnt++;
    }
    return cnt&1;
}
void ip(pnt& s)
{
    scanf("%lf%lf",&s.x,&s.y);
}
int main()
{
    int T=0,fst=1;
    while(scanf("%d",&n),n)
    {
        ++T; scanf("%d",&m);
        for(int i=0;i<n;i++) ip(as[i]);
        if(!fst) puts(""); else fst=0;
        printf("Problem %d:
",T);
        for(int i=0;i<m;i++)
        {
            pnt cur; ip(cur);
            if(chk(cur)) puts("Within"); else puts("Outside");
        }
    }
}

③凸包&旋转卡(qiǎ)壳(qiào) poj2187

其实这题不用旋转卡壳也能过,因为坐标为[0,N]整点的凸包顶点个数是不超过$sqrt{n}$的(当然如果不去除共线的话比较玄学)。

没有旋转卡壳:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <math.h>
#include <limits>
#include <set>
#include <map>
using namespace std;
typedef double ld;
typedef pair<ld,ld> pnt;
#define X first
#define Y second
int n;
pnt yd,a[233333];
ld eps=1e-6;
bool cmp1(pnt a,pnt b)
{
    if(fabs(a.Y-b.Y)>1e-6) return a.Y<b.Y;
    else return a.X<b.X;
}
bool cmp2(pnt a,pnt b)
{return atan2(a.Y-yd.Y,a.X-yd.X)<atan2(b.Y-yd.Y,b.X-yd.X);}
int st[233333],sn=0;
ld cc(pnt a,pnt b,pnt c)
{
    return (a.X-c.X)*(b.Y-c.Y)-(a.Y-c.Y)*(b.X-c.X);
}
ld dis(pnt a,pnt b)
{
    return (a.X-b.X)*(a.X-b.X)+(a.Y-b.Y)*(a.Y-b.Y);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lf%lf",&a[i].X,&a[i].Y);
    sort(a+1,a+1+n,cmp1); yd=a[1]; sort(a+2,a+1+n,cmp2);
    for(int i=1;i<=3;i++) st[++sn]=i;
    for(int i=4;i<=n;i++)
    {
        while(sn>1&&cc(a[i],a[st[sn]],a[st[sn-1]])>=0) --sn;
        st[++sn]=i;
    }
    double maxx=0;
    for(int i=1;i<=sn;i++)
    {
        for(int j=i;j<=sn;j++) maxx=max(maxx,dis(a[st[i]],a[st[j]]));
    }
    printf("%.0lf
",maxx);
}

旋转卡壳:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <math.h>
#include <limits>
#include <set>
#include <map>
using namespace std;
typedef double ld;
typedef pair<ld,ld> pnt;
#define X first
#define Y second
int n;
pnt yd,a[233333];
ld eps=1e-6;
bool cmp1(pnt a,pnt b)
{
    if(fabs(a.Y-b.Y)>1e-6) return a.Y<b.Y;
    else return a.X<b.X;
}
bool cmp2(pnt a,pnt b)
{return atan2(a.Y-yd.Y,a.X-yd.X)<atan2(b.Y-yd.Y,b.X-yd.X);}
int st[233333],sn=0;
ld cc(pnt a,pnt b,pnt c)
{
    return (a.X-c.X)*(b.Y-c.Y)-(a.Y-c.Y)*(b.X-c.X);
}
ld dis(pnt a,pnt b)
{
    return (a.X-b.X)*(a.X-b.X)+(a.Y-b.Y)*(a.Y-b.Y);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lf%lf",&a[i].X,&a[i].Y);
    sort(a+1,a+1+n,cmp1); yd=a[1]; sort(a+2,a+1+n,cmp2);
    for(int i=1;i<=3;i++) st[++sn]=i;
    for(int i=4;i<=n;i++)
    {
        while(sn>1&&cc(a[i],a[st[sn]],a[st[sn-1]])>=0) --sn;
        st[++sn]=i;
    }
    double maxx=0;
    int cur=1;
    for(int i=1;i<=sn;i++)
    {
        while(fabs(cc(a[st[cur%sn+1]],a[st[i%sn+1]],a[st[i]]))>fabs(cc(a[st[cur]],a[st[i%sn+1]],a[st[i]])))
            cur=cur%sn+1;
        maxx=max(maxx,dis(a[st[cur]],a[st[i]]));
        maxx=max(maxx,dis(a[st[cur]],a[st[i%sn+1]]));
    }
    printf("%.0lf
",maxx);
}
原文地址:https://www.cnblogs.com/zzqsblog/p/5419346.html