hdu5251 凸包 旋转卡壳

来源:互联网 发布:幼儿网络学英语 编辑:程序博客网 时间:2024/05/13 14:34

传送门:hdu5251 矩形面积

       接触了旋转卡壳不久,感觉很神奇……

       这个题是要寻找一个矩形来覆盖住桌面上的小矩形,小矩形即四个点啦,所以就是

找一个矩形覆盖住这些点,也就要求一个凸包,再用矩形把凸包盖住,那就很明显的

是旋转卡壳了,类似旋转卡壳求凸包的宽度,只是这是求矩形面积的最小值

完整代码:

#include<cstdio>#include<cmath>#include<algorithm>#include<iostream>using namespace std;const int MAXN=1000005;const double PI=acos(-1.0);typedef long long ll;struct point{    double x,y;};point list[MAXN];point stack[MAXN];int top;/**叉积**/double cross(point p0,point p1,point p2){    return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);}/**点积**/double dot(point p0,point p1,point p2){    return (p1.x-p0.x)*(p2.x-p0.x)+(p1.y-p0.y)*(p2.y-p0.y);}/**距离的平方**/double dis(point p1,point p2){    return (double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y);}/**极角排序**/bool cmp(point p1,point p2){    double tmp=cross(list[0],p1,p2);    if(tmp>0) return true;    else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;    else return false;}/**凸包**/void graham(int n){    int i;    if(n==1) {top=0;stack[0]=list[0];}    if(n==2)    {        top=1;        stack[0]=list[0];        stack[1]=list[1];    }    if(n>2)    {        for(i=0;i<=1;i++) stack[i]=list[i];        top=1;        for(i=2;i<n;i++)        {            while(top>0&&cross(stack[top-1],stack[top],list[i])<=0) top--;            top++;            stack[top]=list[i];        }    }}/**旋转卡壳**/double rotating_calipers(point p[],int n){    int k1=1,k2=1,k3=1;    double ans=0x7FFFFFFF;    p[n]=p[0];    for(int i=0;i<n;i++)    {        /**利用叉积的几何意义,来找距离p[i]-p[i+1]这条边的最远的点**/        while(fabs(cross(p[i],p[i+1],p[k1]))<fabs(cross(p[i],p[i+1],p[k1+1])))            k1=(k1+1)%n;        /**这里求的点积,用了点积的几何意义,即p[i]-p[i+1]这条边再乘p[i]-p[k2]在        p[i]-p[i+1]上的投影,投影的长度便是叉积再除p[i]-p[i+1]的长度,下面在求矩形面积        时用到了这一点**/        while(dot(p[i],p[i+1],p[k2])<dot(p[i],p[i+1],p[k2+1])||dot(p[i],p[i+1],p[k2])<0)            k2=(k2+1)%n;///这里找的是最右边的点,根据几何意义,这里的点积应该是正的        while(dot(p[i],p[i+1],p[k3])>dot(p[i],p[i+1],p[k3+1])||dot(p[i],p[i+1],p[k3])>0)            k3=(k3+1)%n;///这里找的是最左边的点,根据几何意义,这里的点击应该是负的        double tmp=fabs(cross(p[i],p[i+1],p[k1]));        double tmp1=dot(p[i],p[i+1],p[k2]);        double tmp2=dot(p[i],p[i+1],p[k3]);        double d=dis(p[i],p[i+1]);        /**这里求面积,实际是凸包的某一“宽度”(不是严格意义上        的宽度)乘了两个叉积的差就是这个矩形了面积了**/        double s=tmp/d*(tmp1-tmp2);        ans=min(ans,s);    }    return ans;}int main(){    int t;    scanf("%d",&t);    int cnt=0;    while(t--)    {        cnt++;        int n;        scanf("%d",&n);        int k=0;        scanf("%lf%lf",&list[0].x,&list[0].y);        for(int i=1;i<4*n;i++)        {            scanf("%lf%lf",&list[i].x,&list[i].y);            if(list[i].y<list[k].y||(list[i].y==list[k].y&&list[i].x<list[k].x))                k=i;        }        swap(list[k],list[0]);        sort(list+1,list+4*n,cmp);        graham(4*n);        printf("Case #%d:\n%lld\n",cnt,(ll)(rotating_calipers(stack,top+1)+0.5));    }    return 0;}


原创粉丝点击