矩形面积
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 417 Accepted Submission(s): 239
Problem Description
小度熊有一个桌面,小度熊剪了很多矩形放在桌面上,小度熊想知道能把这些矩形包围起来的面积最小的矩形的面积是多少。
Input
第一行一个正整数 T,代表测试数据组数(
1≤T≤20
),接下来 T 组测试数据。
每组测试数据占若干行,第一行一个正整数 N(1≤N<≤1000) ,代表矩形的数量。接下来 N 行,每行 8 个整数 x1,y1,x2,y2,x3,y3,x4,y4 ,代表矩形的四个点坐标,坐标绝对值不会超过10000。
每组测试数据占若干行,第一行一个正整数 N(1≤N<≤1000) ,代表矩形的数量。接下来 N 行,每行 8 个整数 x1,y1,x2,y2,x3,y3,x4,y4 ,代表矩形的四个点坐标,坐标绝对值不会超过10000。
Output
对于每组测试数据,输出两行:
第一行输出"Case #i:",i 代表第 i 组测试数据。
第二行包含1 个数字,代表面积最小的矩形的面积,结果保留到整数位。
第一行输出"Case #i:",i 代表第 i 组测试数据。
第二行包含1 个数字,代表面积最小的矩形的面积,结果保留到整数位。
Sample Input
2 2 5 10 5 8 3 10 3 8 8 8 8 6 7 8 7 6 1 0 0 2 2 2 0 0 2
Sample Output
Case #1: 17 Case #2: 4
Source
Recommend
题解:旋转卡壳求最小面积外接矩形
先对所以矩形的顶点求凸包,然后考虑求凸包的最小面积外接矩形。
有一点很显然就是外接矩形的某条边上一定包含至少两个凸包上的点,其他边至少包含一个。这样才能确定出一个合法的矩形。
所以我们考虑枚举凸包上的相邻两点,确定矩形的一条边所在的直线。然后就是要求到该直线最高,最左,最右的点。这些点随着凸包上边的旋转是单调的。
最高的好判断,直接用点到直线的距离。
最左最右的话,可以用点积,为什么是点积,因为我们要求的两个点一定在该直线上的投影最长,注意向量的方向。
那么矩形的宽也可以用计算投影的方式统计出来。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 10003
#define eps 1e-7
using namespace std;
struct vector{
double x,y;
vector (double X=0,double Y=0){
x=X,y=Y;
}
}a[N],ch[N];
int n,m,cnt;
double ans;
typedef vector point;
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 t){
return vector (a.x*t,a.y*t);
}
bool operator <(vector a,vector b){
return a.x<b.x||a.x==b.x&&a.y<b.y;
}
double cross(vector a,vector b){
return a.x*b.y-a.y*b.x;
}
double dot(vector a,vector b){
return a.x*b.x+a.y*b.y;
}
void convexhull()
{
sort(a+1,a+n+1);
if (n==1) {
ch[m++]=a[1];
return;
}
m=0;
for (int i=1;i<=n;i++){
while (m>1&&cross(ch[m-1]-ch[m-2],a[i]-ch[m-2])<=0) m--;
ch[m++]=a[i];
}
int k=m;
for (int i=n-1;i>=1;i--){
while (m>k&&cross(ch[m-1]-ch[m-2],a[i]-ch[m-2])<=0) m--;
ch[m++]=a[i];
}
m--;
}
int dcmp(double x)
{
if (fabs(x)<eps) return 0;
else return x<0?-1:1;
}
double len(vector a)
{
return sqrt(a.x*a.x+a.y*a.y);
}
double distl(point p,point a,point b)
{
vector v=p-a; vector u=b-a;
return fabs(cross(v,u))/len(u);
}
double calc(point a,point b,point c)
{
double t=dot(a-b,c-a);
t/=len(a-b); t/=len(c-a);
return acos(t);
}
void rotating()
{
ans=1e16;
int i=1,j=1,k=1;
for (int t=2;t<m;t++)
if (distl(ch[t],ch[0],ch[1])>=distl(ch[k],ch[0],ch[1])||t==2)k=t;
for (int t=2;t<m;t++)
if (dot(ch[1]-ch[0],ch[t]-ch[1])>=dot(ch[1]-ch[0],ch[i]-ch[1])||t==2)
i=t;
for (int t=2;t<m;t++)
if (dot(ch[0]-ch[1],ch[t]-ch[0])>=dot(ch[0]-ch[1],ch[j]-ch[0])||t==2) // ch[0]-ch[1] ch[t]-ch[1] 的点积最大,那么投影在向量上的长度就最大。
j=t;
//cout<<dot(ch[1]-ch[0],ch[2]-ch[0])<<" "<<dot(ch[1]-ch[0],ch[3]-ch[0])<<endl;
//cout<<k<<" "<<i<<" "<<j<<endl;
double h=distl(ch[k],ch[0],ch[1]);
double l=len(ch[0]-ch[1])+fabs(dot(ch[1]-ch[0],ch[i]-ch[1]))/len(ch[0]-ch[1])+fabs(dot(ch[0]-ch[1],ch[j]-ch[0]))/len(ch[0]-ch[1]);
ans=min(ans,h*l);
ch[m]=ch[0];
for (int t=1;t<m;t++){
while (distl(ch[k],ch[t],ch[t+1])<=distl(ch[(k+1)%m],ch[t],ch[t+1]))
k=(k+1)%m;
if (i==t+1) i=(i+1)%m;
while (dot(ch[t+1]-ch[t],ch[i]-ch[t+1])<=dot(ch[t+1]-ch[t],ch[(i+1)%m]-ch[t+1]))
i=(i+1)%m;
while (dot(ch[t]-ch[t+1],ch[j]-ch[t])<=dot(ch[t]-ch[t+1],ch[(j+1)%m]-ch[t]))
j=(j+1)%m;
if (j==t) j=((j-1)%m+m)%m;
h=distl(ch[k],ch[t],ch[t+1]);
l=len(ch[t]-ch[t+1])+fabs(dot(ch[t+1]-ch[t],ch[i]-ch[t+1]))/len(ch[t]-ch[t+1])+fabs(dot(ch[t]-ch[t+1],ch[j]-ch[t]))/len(ch[t]-ch[t+1]);
ans=min(ans,h*l);
}
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
int t; scanf("%d",&t);
for (int T=1;T<=t;T++){
scanf("%d",&n); cnt=0;
for (int i=1;i<=n;i++){
for (int j=0;j<4;j++)
++cnt,scanf("%lf%lf",&a[cnt].x,&a[cnt].y);
}
n=cnt;
convexhull();
//for (int i=0;i<m;i++) cout<<ch[i].x<<" "<<ch[i].y<<endl;
rotating();
printf("Case #%d:\n",T);
//printf("%.4lf\n",ans);
printf("%.0lf\n",ans);
}
}