计算几何进阶-旋转卡壳

旋转卡壳的题没什么难度,主要是熟练运用模板和熟悉算法。
A - Beauty Contest
求凸多边形直径模板题,由于都是整数点,极角排序如果用角度而非叉积的话很有可能被卡精度(哭),所以计算几何题尽量还是整数运算吧。。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>

#include<cmath>
using namespace std;
const int maxn=50005;
const double eps=1e-6;
int sgn(double x)
{
    if(fabs(x)<eps)return 0;
    if(x>0)return 1;
    return -1;
}
struct Point
{
    int x,y;
    Point(int _x,int _y):x(_x),y(_y){}
    Point(){}
    Point operator-(const Point &b)const
    {
        return Point(x-b.x,y-b.y);
    }
    double operator *(const Point &b)const
    {
        return x*b.x+y*b.y;
    }
    double operator ^(const Point &b)const
    {
        return x*b.y-y*b.x;
    }
};
Point p[maxn];

double dis(Point a)
{
    return sqrt(0.0+a.x*a.x+a.y*a.y);
}
int dis2(Point a)
{
    return a.x*a.x+a.y*a.y;
}

int xmult(Point a,Point b,Point c)
{
    return (a-c)^(b-c);
}
bool cmp(Point a,Point b)
{
    int tmp=xmult(a,b,p[1]);
    if(tmp>0||tmp==0&&dis2(a-p[1])<dis2(b-p[1]))return true;
    return false;
}
Point ch[maxn];
int N;
int solve()
{
    int n=N;
    ch[1]=p[1],ch[2]=p[2];
    int top=2;
    for(int i=3;i<=n;i++)
    {
        while(top-1>=1&&((p[i]-ch[top-1])^(ch[top]-ch[top-1]))>=0)top--;
        ch[++top]=p[i];
    }
    return top;
}

void solve2(int num)
{
    int p=2;
    int ans=0;
    ch[num+1]=ch[1];
    for(int i=1;i<=num;i++)
    {
        while(xmult(ch[i+1],ch[p+1],ch[i])>xmult(ch[i+1],ch[p],ch[i]))p=p%num+1;
        ans=max(ans,dis2(ch[i]-ch[p]));
        ans=max(ans,dis2(ch[i+1]-ch[p]));
    }
    cout<<ans<<endl;
}

int main()
{
    scanf("%d",&N);
    int x,y;
    for(int i=1;i<=N;i++)
    {
        scanf("%d %d",&x,&y);
        p[i]=Point(x,y);
        if(y<p[1].y||y==p[1].y&&x<p[1].x)
            swap(p[1],p[i]);
    }
    if(N==2)
    {
        cout<<dis2(p[2]-p[1])<<endl;
        return 0;
    }
    sort(p+2,p+N+1,cmp);
    int num=solve();
    /*int ans=0;
    for(int i=1;i<=num;i++)
        for(int j=i+1;j<=num;j++)
        ans=max(ans,dis2(ch[i]-ch[j]));
    cout<<ans<<endl;*/

    if(num==2)
        printf("%d\n",dis2(ch[2]-ch[1]));
    else solve2(num);

}

B - Bridge Across Islands
求凸多边形间最小距离。
没啥坑

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<math.h>
using namespace std;
const int maxn=10005;
const double eps=1e-9;
int sgn(double x)
{
    if(fabs(x)<eps)return 0;
    if(x>0)return 1;
    return -1;
}
struct Point
{
    double x,y;
    Point(){}
    Point(double sx,double sy):x(sx),y(sy){}
    double operator *(const Point &b)const
    {
        return x*b.x+y*b.y;
    }
    double operator^(const Point &b)const
    {
        return x*b.y-y*b.x;
    }
    Point operator-(const Point &b)const
    {
        return Point(x-b.x,y-b.y);
    }
};
Point p1[maxn],p2[maxn];
Point ch1[maxn],ch2[maxn];
int N,M;
Point o;
double dis(Point a)
{
    return sqrt(a.x*a.x+a.y*a.y);
}
bool cmp(Point a,Point b)
{
    double tmp1=atan2(a.y-o.y,a.x-o.x);
    double tmp2=atan2(b.y-o.y,b.x-o.x);
    if(sgn(tmp1-tmp2)!=0)return sgn(tmp1-tmp2)<0;
    return sgn(dis(a-o)-dis(b-o))<0;
}
int graham(int num,Point *p,Point *ch)
{
    for(int i=2;i<=num;i++)
        if(sgn(p[i].y-p[1].y)<0||sgn(p[i].y-p[1].y)==0&&sgn(p[i].x-p[1].x)<0)
            swap(p[i],p[1]);
    o=p[1];
    sort(p+2,p+num+1,cmp);
    ch[1]=p[1],ch[2]=p[2],ch[3]=p[3];
    int top=3;
    for(int i=4;i<=num;i++)
    {
        while(top-1>=1&&sgn((p[i]-ch[top-1])^(ch[top]-ch[top-1]))>=0)top--;
        ch[++top]=p[i];
    }
    return top;
}
typedef const Point CP;
double disptoseg(CP &p,CP &l1,CP &l2)
{
    Point t=p;
    t.x+=l1.y-l2.y,t.y+=l2.x-l1.x;
    if(sgn(((l1-p)^(t-p))*((l2-p)^(t-p)))>0)
        return dis(p-l1)<dis(p-l2)?dis(p-l1):dis(p-l2);
    return fabs(((p-l2)^(l1-l2)))/dis(l1-l2);
}

double dissegtoseg(CP &l1a,CP &l1b,CP &l2a,CP &l2b)
{
    return min(min(disptoseg(l1a,l2a,l2b),disptoseg(l1b,l2a,l2b)),min(disptoseg(l2a,l1a,l1b),disptoseg(l2b,l1a,l1b)));
}

double solve(Point *a,int anum,Point *b,int bnum)
{
    int i;
    double tmp,res=1e10;
    a[anum+1]=a[1],b[bnum+1]=b[1];
    int p,q;
    double ymin=1e5,ymax=-1e5;
    for(i=1;i<=anum;i++)
    {
        if(a[i].y<ymin)
        {
            ymin=a[i].y;
            p=i;
        }
    }
    for(i=1;i<=bnum;i++)
    {
        if(b[i].y>ymax)
        {
            ymax=b[i].y;
            q=i;
        }
    }
    //cout<<p<<' '<<q<<endl;
    for(i=1;i<=anum;i++)
    {
        while(sgn((tmp=((a[p+1]-a[p])^(b[q+1]-a[p]))-((a[p+1]-a[p])^(b[q]-a[p]))))>0)
            q=q%bnum+1;
        if(sgn(tmp)<0)res=min(res,disptoseg(b[q],a[p],a[p+1]));
        else res=min(res,dissegtoseg(a[p],a[p+1],b[q],b[q+1]));
        p=p%anum+1;
        //cout<<res<<endl;
    }
    return res;
}

int main()
{
    //freopen("input.txt","r",stdin);
    while(~scanf("%d %d",&N,&M))
    {
        if(N==0&&M==0)break;
        double x,y;
        for(int i=N;i>=1;i--)
        {
            scanf("%lf %lf",&x,&y);
            p1[i]=Point(x,y);
        }
        for(int i=M;i>=1;i--)
        {
            scanf("%lf %lf",&x,&y);
            p2[i]=Point(x,y);
        }
        int p1num=graham(N,p1,ch1);
        int p2num=graham(M,p2,ch2);
        //cout<<p1num<<endl;
        //cout<<p2num<<endl;
        double tmp=solve(ch1,p1num,ch2,p2num);
        printf("%.5f\n",min(tmp,solve(ch2,p2num,ch1,p1num)));
    }
    return 0;

}

C - Triangle
我不太理解它这个做法的正确性。。但十分有道理。。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<math.h>

using namespace std;
const double eps=1e-9;
const int maxn=50005;

int sgn(double x)
{
    if(fabs(x)<eps)return 0;
    if(x>0)return 1;
    return -1;
}

struct Point
{
    int x,y;
    Point() {}
    Point(int sx,int sy):x(sx),y(sy) {}
    double operator*(const Point &b)const
    {
        return x*b.x+y*b.y;
    }
    double operator^(const Point &b)const
    {
        return x*b.y-y*b.x;
    }
    Point operator-(const Point &b)const
    {
        return Point(x-b.x,y-b.y);
    }
};
Point p[maxn];
Point ch[maxn];
int n;

long long dis2(Point a)
{
    return a.x*a.x+a.y*a.y;
}

bool cmp(Point a,Point b)
{
    double tmp1=atan2(a.y-p[1].y,a.x-p[1].x);
    double tmp2=atan2(b.y-p[1].y,b.x-p[1].x);
    if(sgn(tmp1-tmp2)!=0)return sgn(tmp1-tmp2)<0;
    return dis2(a-p[1])-dis2(b-p[1])<0;
}
int xmult(Point a,Point b,Point c)
{
    return (a-c)^(b-c);
}
int top;
void graham()
{
    sort(p+2,p+n+1,cmp);
    ch[1]=p[1],ch[2]=p[2],ch[3]=p[3];
    top=3;
    for(int i=4; i<=n; i++)
    {
        while(top-1>=1&&xmult(p[i],ch[top],ch[top-1])>=0)top--;
        ch[++top]=p[i];
    }
}

void solve()
{
    int p=2,q=3;
    int ans=0;
    ch[top+1]=ch[1];
    for(int i=1; i<=top; i++)
    {
        while(xmult(ch[p],ch[q+1],ch[i])>xmult(ch[p],ch[q],ch[i]))q=q%top+1;
        ans=max(ans,xmult(ch[p],ch[q],ch[i]));
        while(xmult(ch[p+1],ch[q],ch[i])>xmult(ch[p],ch[q],ch[i]))p=p%top+1;
        ans=max(ans,xmult(ch[p],ch[q],ch[i]));
    }
    printf("%.2f\n",1.0*ans/2);
}
int main()
{
    //freopen("input.txt","r",stdin);
    while(~scanf("%d",&n)&&n!=-1)
    {
        int x,y;
        for(int i=1; i<=n; i++)
        {
            scanf("%d %d",&x,&y);
            p[i]=Point(x,y);
            if(y<p[1].y||y==p[1].y&&x<p[1].x)
                swap(p[1],p[i]);
        }
        if(n<3)puts("0.00");
        else graham(),solve();
    }
    return 0;

}

D - Smallest Bounding Rectangle
最小外接矩形面积
讲道理没啥坑,主要我凸包写搓了,wa了10几发。。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<math.h>
using namespace std;
const double eps=1e-8;
const int maxn=1005;
int sgn(double x)
{
    if(fabs(x)<eps)return 0;
    if(x>0)return 1;
    return -1;
}
struct Point
{
    double x,y;
    Point(){}
    Point(double sx,double sy):x(sx),y(sy){}
    double operator*(const Point &b)const
    {
        return x*b.x+y*b.y;
    }
    double operator^(const Point &b)const
    {
        return x*b.y-y*b.x;
    }
    Point operator-(const Point &b)const
    {
        return Point(x-b.x,y-b.y);
    }

};
Point p[maxn];
Point ch[maxn];
double dis(Point a)
{
    return sqrt(a.x*a.x+a.y*a.y);
}
bool cmp(Point a,Point b)
{
    double tmp1=atan2(a.y-p[1].y,a.x-p[1].x);
    double tmp2=atan2(b.y-p[1].y,b.x-p[1].x);
    if(sgn(tmp1-tmp2)!=0)return sgn(tmp1-tmp2)<0;
    return sgn(dis(a-p[1])-dis(b-p[1]))<0;
}
double xmult(Point a,Point b,Point c)
{
    return (a-c)^(b-c);
}
double dot(Point a,Point b,Point c)
{
    return (a-c)*(b-c);
}
int n;
int graham()
{
    sort(p+2,p+n+1,cmp);
    ch[1]=p[1],ch[2]=p[2];
    int top=2;
    for(int i=3;i<=n;i++)
    {
        while(top-1>=1&&sgn(xmult(p[i],ch[top],ch[top-1]))>=0)top--;
        ch[++top]=p[i];
    }
    return top;
}

double solve(int num)
{
    int r=2,q=2,p;
    double res=1e10;
    ch[num+1]=ch[1];
    for(int i=1;i<=num;i++)
    {
        while(sgn(xmult(ch[i+1],ch[r+1],ch[i])-xmult(ch[i+1],ch[r],ch[i]))>0)r=r%num+1;
        while(sgn(dot(ch[i+1],ch[q+1],ch[i])-dot(ch[i+1],ch[q],ch[i]))>0)q=q%num+1;
        if(i==1)p=q;
        while(sgn(dot(ch[i+1],ch[p+1],ch[i])-dot(ch[i+1],ch[p],ch[i]))<=0)p=p%num+1;
        double a=xmult(ch[i+1],ch[r],ch[i]);
        double b=dot(ch[i+1],ch[q],ch[i])-dot(ch[i+1],ch[p],ch[i]);
        double c=dot(ch[i+1],ch[i+1],ch[i]);
        res=min(res,a*b/c);
    }
    return res;
}

int main()
{
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    while(~scanf("%d",&n)&&n)
    {
        double x,y;
        for(int i=1;i<=n;i++)
        {
            scanf("%lf %lf",&x,&y);
            p[i]=Point(x,y);
            if(sgn(y-p[1].y)<0||sgn(y-p[1].y)==0&&sgn(x-p[1].x)<0)
                swap(p[1],p[i]);
        }
        if(n<=2){puts("0.0000");continue;}
        int num=graham();
        //cout<<num<<endl;
        if(num<=2){puts("0.0000");continue;}
        double ans=solve(num);
        printf("%.4lf\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值