UVa 819- Gifts Large and Small

来源:互联网 发布:哈尔滨网络电视台 编辑:程序博客网 时间:2024/06/05 16:58

感谢vfk几个月前提供的思路………

提示:(详解在代码后)

  • 整个包装肯定要包围凸包
  • 可以试试长方形的两条边都是平行的 , 所以联想到某一种转来转去的东西
  • 如果知道了一条边的Vector , 其实两对Vector 都知道了
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <vector>#include <deque>#include <algorithm>#include <list>#include <queue>using namespace std;const int maxn = 110;const double eps = 1e-10;const double pi = acos(-1);int dcmp(double a) { return fabs(a)<eps?0:(a<0?-1:1); }struct points{    double x , y;    void read(){ scanf("%lf%lf",&x,&y); }    points(double x = 0 , double y = 0):x(x),y(y){}    bool operator <(const points& b)const { return dcmp(x-b.x)==-1 || (dcmp(x-b.x)==0 && dcmp(y-b.y)==-1); }    bool operator ==(const points& b)const { return dcmp(x-b.x)==0 && dcmp(y-b.y)==0; }};typedef points Vector;typedef vector<points> polygon;const Vector seaLevel = Vector(10 , 0);Vector operator +(Vector a , Vector b) { return Vector(a.x+b.x , a.y+b.y); }Vector operator -(Vector a , Vector b) { return Vector(a.x-b.x , a.y-b.y); }Vector operator *(Vector a , double b) { return Vector(a.x*b , a.y*b); }Vector operator /(Vector a , double b) { return Vector(a.x/b  , a.y/b); }Vector Rotate(Vector a , double rad) { return Vector(a.x*cos(rad)-a.y*sin(rad) , a.x*sin(rad)+a.y*cos(rad)); }double Dot(Vector a , Vector b) { return a.x*b.x+a.y*b.y; }double Cross(Vector a , Vector b) { return a.x*b.y-a.y*b.x; }double Length(Vector a) { return sqrt(Dot(a , a)); }double angle(Vector a) { return atan2(a.y , a.x); }//double angle(Vector a , Vector b) //{ double hi = Dot(a , b)/Length(a)/Length(b); if(dcmp(fabs(hi)-1)==0) return hi<0?acos(-1):acos(1); return acos(hi);  }double angle(Vector a , Vector b)  { return atan2(Cross(a, b) , Dot(a, b)); }double turnAngle(Vector a , Vector b) { return dcmp(Dot(a , b))==1?angle(a , b):pi+angle(a , b); }points ch[maxn];int convexHull(polygon& p){    sort(p.begin() , p.end());    p.erase(unique(p.begin() , p.end()) , p.end());    int n = p.size();    int m = 0;    for(int i=0;i<n;i++)    {        while(m>1 && dcmp(Cross(ch[m-1]-ch[m-2] , p[i]-ch[m-2]))<0) m--;        ch[m++] = p[i];    }    int k = m;    for(int i=n-2;i>=0;i--)    {        while(m>k && dcmp(Cross(ch[m-1]-ch[m-2] , p[i]-ch[m-2]))<0) m--;        ch[m++] = p[i];    }    if(n>1) m--;    return m;}double distanceOfPointsAndLine(points a ,points b , points c) { return fabs(Cross(b-a , c-a)/Length(b-c)); }double Area(int a , int b , int c , int d , Vector ab , Vector cd){    double h1 = distanceOfPointsAndLine(ch[a] , ch[b] , ch[b]+ab);    double h2 = distanceOfPointsAndLine(ch[c] , ch[d] , ch[d]+cd);    return h1*h2;}int main(){//  freopen("in","r",stdin);    int n , Case=0;    while(cin>>n && n)    {        points now;        polygon po;        for(int i=0;i<n;i++)        {            now.read();            po.push_back(now);        }        int m = convexHull(po);//      cout<<m<<endl;        ch[m] = ch[0];        double Min = 1e20 , Max = -1;        double Minx=ch[0].x , Miny=ch[0].y , Maxx=ch[0].x , Maxy=ch[0].y;        int p1=0 , p2=0 , p3=0 , p4=0;        Vector v1 , v2 , ori;        ori = v1 = Vector(1,0);        v2 = Vector(0,1);        for(int i=1;i<m;i++)        {            if(dcmp(Minx - ch[i].x)==1) Minx = ch[i].x , p3 = i;            if(dcmp(Maxx - ch[i].x)==-1) Maxx = ch[i].x , p4 = i;            if(dcmp(Miny - ch[i].y)==1) Miny= ch[i].y , p1 = i;            if(dcmp(Maxy - ch[i].y)==-1) Maxy = ch[i].y , p2 = i;        }        while(dcmp(Cross(ori , v1))>=0)        {            double minRad = 1e20;            minRad = min(minRad , turnAngle(v1 , ch[p1+1]-ch[p1]));            minRad = min(minRad , turnAngle(v1*(-1) , ch[p2+1]-ch[p2]));            minRad = min(minRad , turnAngle(v2*(-1) , ch[p3+1]-ch[p3]));            minRad = min(minRad , turnAngle(v2 , ch[p4+1]-ch[p4]));//          cout<<minRad<<endl;                 double l = 0 , r = minRad;                Min = min(Min , Area(p1 , p2 , p3 , p4 , Rotate(v1 , l) , Rotate(v2 , l)));                while(dcmp(l-r))                {                    double len = (r-l)/3;                    double midl = l+len;                    double midr = r-len;                    if(dcmp(Area(p1 , p2 , p3 , p4 , Rotate(v1 , midl) , Rotate(v2 , midl)) - Area(p1 , p2 , p3 , p4 , Rotate(v1 , midr) , Rotate(v2 , midr)))==1) r = midr;                    else l = midl;                }                Max = max(Max ,Area(p1 , p2 , p3 , p4 , Rotate(v1 , l) , Rotate(v2 , l)));            v1 = Rotate(v1, minRad);            v2 = Rotate(v2 , minRad);            if(dcmp(angle(v1 , ch[p1+1]-ch[p1]))==0) p1 = (p1+1)%m;            if(dcmp(angle(v1*(-1) , ch[p2+1]-ch[p2]))==0) p2 = (p2+1)%m;            if(dcmp(angle(v2*(-1) , ch[p3+1]-ch[p3]))==0) p3 = (p3+1)%m;            if(dcmp(angle(v2 , ch[p4+1]-ch[p4]))==0) p4 = (p4+1)%m;        }        printf("Gift %d\nMinimum area = %.3lf\nMaximum area = %.3lf\n\n",++Case, Min, Max);    }    return 0;}

详解:

  • 旋转卡壳 , 对 , 就是它。 这种方法在训练指南上有一道例题 , 其中提到的实现方法很不错。 但我没有办法应用到这个题上…

  • 对于这个题 , 我们需要维护四个量 , 即两对对踵点 , 还有一个此时的角度(任意一个Vector其实都是可以的 , 但这里方便实现用了两个Vector)

  • 这个题需要求最大和最小包围矩形 , 但是旋转角度是一个连续的量 , 也就是说我们不能像处理离散量一样枚举每一种情况。

  • 由于这个矩形的面积由角度这个变量唯一决定 , 而任意一个三角函数在一个区间大小小于pi 的情形下都是单峰的 , 所以 , 三分吧

BTW:
单峰 , 极值处取到最大值留给大家思考(想想这玩意用的是哪个三角函数啊)

0 0
原创粉丝点击