接触了旋转卡壳不久,感觉很神奇……
这个题是要寻找一个矩形来覆盖住桌面上的小矩形,小矩形即四个点啦,所以就是
找一个矩形覆盖住这些点,也就要求一个凸包,再用矩形把凸包盖住,那就很明显的
是旋转卡壳了,类似旋转卡壳求凸包的宽度,只是这是求矩形面积的最小值
完整代码:
#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;
}