1. 程式人生 > >hdu 5251 矩形面積 (旋轉卡殼求最小面積外接矩形)

hdu 5251 矩形面積 (旋轉卡殼求最小面積外接矩形)

矩形面積

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,代表測試資料組數(1T20),接下來 T 組測試資料。

每組測試資料佔若干行,第一行一個正整數 N(1N<1000),代表矩形的數量。接下來 N 行,每行 8 個整數x
1
,y1,x2,y2,x3,y3,x4,y4
,代表矩形的四個點座標,座標絕對值不會超過10000。

Output 對於每組測試資料,輸出兩行:

第一行輸出"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 hujie   |   We have carefully selected several similar problems for you:  
6010
 6009 6008 6007 6006 

題解:旋轉卡殼求最小面積外接矩形

先對所以矩形的頂點求凸包,然後考慮求凸包的最小面積外接矩形。

有一點很顯然就是外接矩形的某條邊上一定包含至少兩個凸包上的點,其他邊至少包含一個。這樣才能確定出一個合法的矩形。

所以我們考慮列舉凸包上的相鄰兩點,確定矩形的一條邊所在的直線。然後就是要求到該直線最高,最左,最右的點。這些點隨著凸包上邊的旋轉是單調的。

最高的好判斷,直接用點到直線的距離。

最左最右的話,可以用點積,為什麼是點積,因為我們要求的兩個點一定在該直線上的投影最長,注意向量的方向。

那麼矩形的寬也可以用計算投影的方式統計出來。

#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);
	}
}