1185: [HNOI2007]最小矩形覆盖

1185: [HNOI2007]最小矩形覆盖

Time Limit: 10 Sec   Memory Limit: 162 MBSec   Special Judge
Submit: 1392   Solved: 627
[ Submit][ Status][ Discuss]

Description

1185: [HNOI2007]最小矩形覆盖_第1张图片 

1185: [HNOI2007]最小矩形覆盖_第2张图片

Input

Output

Sample Input

Sample Output

HINT

Source

计算几何 vfleaking提供Spj

[ Submit][ Status][ Discuss]



因为要矩形的面积最小,,所以肯定四条边上都要有一些点

这样的话这个矩形一定是在凸包上的,先求一下凸包,然后枚举每条边,就等于确定了一条边所在直线

对于一个矩形,确定了一条边上的直线,对边平行,另两条边垂直

这样的话旋转卡壳就可以卡出另外三条直线了。。。。。这样做O(nlogn)就行

不过有个点有出现重点,搞得凸包尴尬了。。先去重就没事了

#include
#include
#include
#include
#include
#include
#include
using namespace std;

const int maxn = 5E4 + 50;
typedef double DB;
const DB eps = 1E-5;
bool fcmp(DB x,DB y) {return fabs(x - y) <= eps;}

struct Point{
	DB x,y; Point(){}
	Point(DB x,DB y): x(x),y(y){}
	Point operator - (const Point &b) {return Point(x - b.x,y - b.y);}
	Point operator + (const Point &b) {return Point(x + b.x,y + b.y);}
	Point operator * (const DB &t) {return Point(x*t,y*t);}
	Point operator / (const DB &t) {return Point(x/t,y/t);}
	bool operator < (const Point &b) const
	{
		if (x < b.x) return 1;
		if (x > b.x) return 0;
		return y < b.y;
	}
	bool operator != (const Point &b) const
	{
		return !fcmp(x,b.x) || !fcmp(y,b.y);
	}
}p[maxn],h[maxn*2],s[4];
typedef Point Vector;

struct Line{
	Point P; Vector V; Line(){}
	Line(Point P,Vector V): P(P),V(V){}
};

int n,tp,H,cur = 1;
DB Ans = 1E18;

int nex(int x) {return x < tp?x + 1:1;}
DB Dot(Vector v1,Vector v2) {return v1.x*v2.x + v1.y*v2.y;}
DB Cross(Vector v1,Vector v2) {return v1.x*v2.y - v2.x*v1.y;}
bool OnLeft(Line L1,Line L2) 
{
	DB ret = Cross(L2.V,L1.P - L2.P);
	return ret > 0.0000;
}
DB Length(Vector v) {return sqrt(Dot(v,v));}

Point GetIntersection(Line L1,Line L2)
{
	Vector u = L1.P - L2.P;
	return L1.P + L1.V*Cross(L2.V,u)/Cross(L1.V,L2.V);
}

void Calc(Line A,Line B,Line C,Line D)
{
	Point a = GetIntersection(D,A),b = GetIntersection(A,B);
	Point c = GetIntersection(B,C),d = GetIntersection(C,D);
	DB Now = Length(b - a)*Length(c - b);
	if (Now >= Ans) return;
	Ans = Now; s[0] = a; s[1] = b; s[2] = c; s[3] = d;
}

void Get_Hull()
{
	for (int i = 1; i <= n; i++)
	{
		DB x,y; scanf("%lf%lf",&x,&y);
		p[i] = Point(x,y);
	}
	sort(p + 1,p + n + 1);
	for (int i = 2; i <= n; i++)
		if (p[i] != p[i-1]) p[++cur] = p[i];
	n = cur;
	for (int i = 1; i <= n; i++)
	{
		while (tp > 1 && Cross(p[i] - h[tp-1],h[tp] - h[tp-1]) > 0.00) 
			--tp; h[++tp] = p[i];
	}
	H = tp;
	for (int i = n - 1; i; i--)
	{
		while (tp > H && Cross(p[i] - h[tp-1],h[tp] - h[tp-1]) > 0.00)
			--tp; h[++tp] = p[i];
	}
}

void Print(DB x) 
{
	if (fcmp(x,0.00000)) printf("0.00000"); 
	else printf("%.5f",x);
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	cin >> n; Get_Hull(); --tp;
	int b = 2,c,d; c = d = H;
	for (int a = 1; a <= tp; a++)
	{
		Vector A = h[nex(a)] - h[a],B = Point(-A.y,A.x);
		Vector C = Point(-A.x,-A.y),D = Point(A.y,-A.x);
		while (OnLeft(Line(h[b],B),Line(h[nex(b)],B))) b = nex(b);
		while (OnLeft(Line(h[c],C),Line(h[nex(c)],C))) c = nex(c);
		while (OnLeft(Line(h[d],D),Line(h[nex(d)],D))) d = nex(d);
		Calc(Line(h[a],A),Line(h[b],B),Line(h[c],C),Line(h[d],D));
	}
	printf("%.5f\n",Ans); int pos = 0;
	for (int i = 1; i < 4; i++)
		if (s[i].y < s[pos].y) pos = i;
		else if (fcmp(s[i].y,s[pos].y) && s[i].x < s[pos].x) pos = i;
	for (int i = pos; ;)
	{
		Print(s[i].x); cout << ' ';
		Print(s[i].y); cout << endl;
		i = i == 3?0:i + 1; if (i == pos) break;
	}
	return 0;
}

你可能感兴趣的:(凸包,旋转卡壳)