感谢vfk几个月前提供的思路………
提示:(详解在代码后)
#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:
单峰 , 极值处取到最大值留给大家思考(想想这玩意用的是哪个三角函数啊)