凸包+旋转卡壳专题

洛谷P2742

求凸包周长

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e4+1;
const double eps=1e-8;
struct point
{
    double x,y;
    point(){}
    point(double a,double b)
    {
        x=a;y=b;
    }
    point operator -(const point &a)const//向量差
    {
        return point(x-a.x,y-a.y);
    }
    double operator ^(const point &a)const//向量叉乘
    {
        return x*a.y-y*a.x;
    }
    double operator *(const point &a)const//向量点乘
    {
        return x*a.x+y*a.y;
    }
}p[MAX],b[MAX];
int top,n;
double cross(point a,point b,point c)//叉积(三角形面积*2
{
    return (b-a)^(c-a);
}
double dis(point a,point b)//两点距离sqrt(dis)
{
    return (a-b)*(a-b);
}
bool cmp(point a,point b)
{
    double tmp=cross(p[0],a,b);
    if(tmp>eps||(fabs(tmp)<eps&&dis(p[0],a)-dis(p[0],b)>eps)) return 1;
    return 0;
}
void graham()
{
    int u=0;top=0;
    for(int k=1;k<n;k++)
        if(p[u].y-p[k].y>eps||(fabs(p[u].y-p[k].y)<eps&&p[u].x-p[k].x>eps))
            u=k;
    swap(p[u],p[0]);
    sort(p+1,p+n,cmp);
    if(n>0) {b[0]=p[0];top++;}
    if(n>1) {b[1]=p[1];top++;}
    if(n<3) return ;
    for(int i=2;i<n;i++)
    {
        while(top>1&&cross(b[top-2],b[top-1],p[i])<eps) top--;
        b[top++]=p[i];
    }
}
int main()
{
    double sum=0;
    scanf("%d",&n);
    for(int k=0;k<n;k++)
        scanf("%lf%lf",&p[k].x,&p[k].y);
    graham();
    b[top]=b[0];
    for(int k=1;k<=top;k++)
        sum+=sqrt(dis(b[k],b[k-1]));
    printf("%.2f\n",sum);
    return 0;
}

POJ3348 Cows

求凸包面积

int main()
{
    double sum=0;
    scanf("%d",&n);
    for(int k=0;k<n;k++)
        scanf("%lf%lf",&p[k].x,&p[k].y);
    graham();
    for(int k=1;k<top-1;k++)
        sum+=fabs(cross(b[0],b[k],b[k+1]));//凸包中的三角形叉积和
    printf("%d\n",(int)(sum/100));
    return 0;
}

POJ2187 Beauty Contest

旋转卡壳 求最远点对

double rotating()
{
    double ans=0;
    b[top]=b[0];
    for(int k=0,i=1;k<=top;k++)
    {
        while(fabs(cross(b[k],b[i+1],b[k+1]))-fabs(cross(b[k],b[i],b[k+1]))>eps)
            i=(i+1)%top;
        ans=max(ans,dis(b[i],b[k]));
    }
    return ans;
}

旋转卡壳 求凸包最小宽度

double rotating()
{
    double ans=0x3f3f3f3f;
    b[top]=b[0];
    for(int k=0,i=1;k<=top;k++)
    {
        while(fabs(cross(b[k],b[i+1],b[k+1]))-fabs(cross(b[k],b[i],b[k+1]))>eps)
            i=(i+1)%top;
        ans=min(ans,fabs(cross(b[k],b[k+1],b[i])/sqrt(dis(b[k],b[k+1]))));
    }
    return ans;
}

HDU2202 最大三角形

旋转卡壳 求平面最大三角形

double rotating()
{
    double ans=0;
    for(int k=0;k<top;k++)
    {
        int i=(k+1)%top;
        int j=(i+1)%top;
        while(i!=k&&j!=k)
        {
            ans=max(ans,fabs(cross(b[k],b[i],b[j])));
            while(fabs(cross(b[k],b[i+1],b[j]))-fabs(cross(b[k],b[i],b[j]))>eps)
                i=(i+1)%top;
            j=(j+1)%top;
        }
    }
    return ans;
}

POJ3608 Bridge Across Islands

旋转卡壳 求两凸包最近距离(min)   /  最远距离(max)

#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
const int MAX=1e4+5;
const double eps=1e-8;
const double INF=1e99;
struct point
{
    double x,y;
    point(){}
    point(double a,double b)
    {
        x=a;y=b;
    }
    point operator -(const point &a)const//向量差
    {
        return point(x-a.x,y-a.y);
    }
    double operator ^(const point &a)const//向量叉乘
    {
        return x*a.y-y*a.x;
    }
    double operator *(const point &a)const//向量点乘
    {
        return x*a.x+y*a.y;
    }
}p[MAX],b1[MAX],b2[MAX];
int top1,top2;
double min(double a,double b)
{
    return a-b<-eps?a:b;
}
double cross(point a,point b,point c)//叉积(三角形面积*2
{
    return (b-a)^(c-a);
}
double multi(point a,point b,point c)//点积
{
    return (b-a)*(c-a);
}
double dis(point a,point b)//两点距离sqrt(dis)
{
    return (a-b)*(a-b);
}
double dist(point a,point b,point c)//点线段最短距离a\bc
{
    point d;
    double t=multi(b,a,c)/dis(b,c);
    if(t>-eps&&t-1<eps) d=point(b.x+(c.x-b.x)*t,b.y+(c.y-b.y)*t);
    else
    {
        if(dis(a,b)-dis(a,c)<-eps) d=b;
        else d=c;
    }
    return dis(a,d);
}
//double dist(point a,point b,point c)//sqrt(dis)下
//{
//    if(dis(b,c)<eps) return dis(a,c);
//    if(multi(b,c,a)<-eps) return dis(a,b);
//    if(multi(c,b,a)<-eps) return dis(a,c);
//    return fabs(cross(b,c,a)/dis(b,c));
//}
double distence(point a,point b,point c,point d)//两线段距离ab\cd
{
    return min(min(dist(a,c,d),dist(b,c,d)),min(dist(c,a,b),dist(d,a,b)));
}
bool cmp(point a,point b)
{
    double tmp=cross(p[0],a,b);
    if(tmp>eps||(fabs(tmp)<eps&&dis(p[0],a)-dis(p[0],b)>eps)) return 1;
    return 0;
}
void graham(point *b,int n,int &top)
{
    int u=0;top=0;
    for(int k=1;k<n;k++)
        if(p[u].y-p[k].y>eps||(fabs(p[u].y-p[k].y)<eps&&p[u].x-p[k].x>eps))
            u=k;
    swap(p[u],p[0]);
    sort(p+1,p+n,cmp);
    if(n>0) {b[0]=p[0];top++;}
    if(n>1) {b[1]=p[1];top++;}
    if(n<3) return ;
    for(int i=2;i<n;i++)
    {
        while(top>1&&cross(b[top-2],b[top-1],p[i])<eps) top--;
        b[top++]=p[i];
    }
}
double rotating(point *a,int n,point *b,int m)
{
    int i1=0,i2=0;
    for(int k=0;k<n;k++)
        if(a[k].y-a[i1].y<-eps) i1=k;
    for(int k=0;k<m;k++)
        if(b[k].y-b[i2].y>eps) i2=k;
    a[n]=a[0];b[m]=b[0];
    double tmp,ans=INF;
    for(int k=0;k<n;k++)
    {
        while((tmp=cross(a[i1+1],b[i2+1],a[i1])-cross(a[i1+1],b[i2],a[i1]))>eps)
            i2=(i2+1)%m;
        if(tmp<-eps) ans=min(ans,dist(b[i2],a[i1],a[i1+1]));
        else ans=min(ans,distence(a[i1],a[i1+1],b[i2],b[i2+1]));
        i1=(i1+1)%n;
    }
    return ans;
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m)&&(n||m))
    {
        for(int k=0;k<n;k++) scanf("%lf%lf",&p[k].x,&p[k].y);
        graham(b1,n,top1);
        for(int k=0;k<m;k++) scanf("%lf%lf",&p[k].x,&p[k].y);
        graham(b2,m,top2);
        //G++编译时double 和float 都只能用%f输出,float转为double,C++不影响,比赛时一般以G++为准
        printf("%0.5f\n",sqrt(min(rotating(b1,top1,b2,top2),rotating(b2,top2,b1,top1))));
    }
    return 0;
}

*关于ACM竞赛中G++(ming32/linux)C++编译的注意事项

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值