1. 程式人生 > >hdu2202:最大三角形(凸包旋轉卡殼求最大三角形面積)

hdu2202:最大三角形(凸包旋轉卡殼求最大三角形面積)

Problem Description

老師在計算幾何這門課上給Eddy佈置了一道題目,題目是這樣的:給定二維的平面上n個不同的點,要求在這些點裡尋找三個點,使他們構成的三角形擁有的面積最大。 Eddy對這道題目百思不得其解,想不通用什麼方法來解決,因此他找到了聰明的你,請你幫他解決這個題目。

 

Input

輸入資料包含多組測試用例,每個測試用例的第一行包含一個整數n,表示一共有n個互不相同的點,接下來的n行每行包含2個整數xi,yi,表示平面上第i個點的x與y座標。你可以認為:3 <= n <= 50000 而且 -10000 <= xi, yi <= 10000.

 

Output

對於每一組測試資料,請輸出構成的最大的三角形的面積,結果保留兩位小數。 每組輸出佔一行。

 

Sample Input

3

3 4

2 6

3 7

6

2 6

3 9

2 0

8 0

6 6

7 7

 

Sample Output

1.50

27.00

題意是先給你n個點求出可以構成的最大三角形的面積。

這個面積最大的三角形的三個頂點一定是凸包上的三個點。

先求出凸包上的所有點,然後暴力三角形的兩點,找最後一個點。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
const int maxn = 200005;

struct point {
	double x, y;
	point(double x = 0, double y = 0):x(x),y(y) {};
};
struct segment { //線段
	point a, b;
};

double dis(point p1, point p2) {
	return sqrt((p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));   //距離
}
double cross(point A,point B) {
	return A.x*B.y-A.y*B.x;   //叉乘
}
//返回結果為正說明p2在向量p0p1的左邊(三點構成逆時針方向);為負則相反;為0則三點共線(叉積的性質很重要)
double cross(point p0,point p1,point p2) {
	return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
double min(double a, double b, double c) {
	return min(a, min(b, c));
}
double max(double a, double b, double c) {
	return max(a, max(b, c));
}
int dcmp(double x) { //判斷x是=0(0), >0(1), <0(-1);
	if(fabs(x)<eps) return 0;
	return x<0?-1:1;
}
int dcmp(ll x) { //判斷x是=0(0), >0(1), <0(-1);
	if(x==0) return 0;
	return x<0?-1:1;
}
point operator + (point A,point B) {
	return point(A.x+B.x,A.y+B.y);
}
point operator - (point A,point B) {
	return point(A.x-B.x,A.y-B.y);
}
point operator * (point A,double p) {
	return point(A.x*p,A.y*p);
}
point operator / (point A,double p) {
	return point(A.x/p,A.y/p);
}
bool operator == (point A,point B) {
	return dcmp(A.x - B.x)==0&&dcmp(A.y-B.y)==0;
}

bool Exclusion(segment p,segment q) { //快速排斥試驗
	if(min(p.a.x,p.b.x)-max(q.a.x,q.b.x)>eps||min(p.a.y,p.b.y)-max(q.a.y,q.b.y)>eps||min(q.a.x,q.b.x)-max(p.a.x,p.b.x)>eps||min(q.a.y,q.b.y)-max(p.a.y,p.b.y)>eps)
		return 0;
	return 1;
}
bool Straddling(segment p,segment q) { //跨立實驗
	if(dcmp(cross(p.b-p.a,q.a-p.a))*dcmp(cross(p.b-p.a,q.b-p.a))<=0&&dcmp(cross(q.b-q.a,p.a-q.a))*dcmp(cross(q.b-q.a,p.b-q.a))<=0)
		return 1;
	return 0;
}
bool check(segment p,segment q) { //判斷兩線段是否相交
	if(Exclusion(p, q) && Straddling(p,q))
		return 1;
	return 0;
}
/*------------------------------------------------------------------------------------*/

point plist[maxn], pstack[maxn];
bool cmp(const point &p1, const point &p2) {
	double tmp = cross(plist[0], p1, p2);
	if (tmp > 0.0)return true;
	else if (tmp == 0.0 && dis(plist[0], p1) < dis(plist[0], p2))return true;
	else return false;
}

void init(int n) {
	int k = 0;
	scanf("%lf%lf", &plist[0].x, &plist[0].y);
	for (int i = 1; i < n; i++) {
		scanf("%lf%lf", &plist[i].x, &plist[i].y);
		if ((plist[k].y > plist[i].y) || ((plist[k].y == plist[i].y) && (plist[k].x > plist[i].x)))
			k = i;
	}
	swap(plist[0], plist[k]);
	sort(plist+1,plist+n,cmp);
}

int Graham(int n) {
	if(n == 1)
		return 1;
	int top = 1;
	pstack[0] = plist[0];
	pstack[1] = plist[1];
	for (int i = 2; i < n; i++) {
		while (top>0 && cross(pstack[top - 1], pstack[top], plist[i]) <= 0)top--;
		pstack[++top] = plist[i];
	}
	return top + 1;
}

double convex_minlen(int n) {
	if(n == 1)
		return 0;
	if(n == 2)
		return dis(pstack[0], pstack[1]);
	double ans = 0;
	int k = 0;
	pstack[n] = pstack[0];
	for (int i = 0; i < n; i++) {
		while(cross(pstack[i], pstack[i + 1], pstack[k]) < cross(pstack[i], pstack[i + 1], pstack[k + 1])) {
			k = (k + 1) % n;
		}
		double t1 = dis(pstack[i], pstack[k]);
		double t2 = dis(pstack[i + 1], pstack[k]);
		ans = max(ans, t1, t2);
	}
	return ans;
}
double convex_maxlen(int n) {
	if(n == 1)
		return 0;
	if(n == 2)
		return dis(pstack[0], pstack[1]);
	double ans = 0;

	for (int i = 0; i < n - 1; i++) {
		int k = 0;
		for (int j = i + 1; j < n; j++) {
			while (cross(pstack[i], pstack[j], pstack[k]) < cross(pstack[i], pstack[j], pstack[k + 1])) {
				k = (k + 1) % n;
			}
			ans = max(cross(pstack[i], pstack[j], pstack[k]) / 2.0, ans);
		}
	}
	return ans;
}


int main() {
	int n;
	while(scanf("%d",&n) != EOF) {
		init(n);
		n = Graham(n);
		double ans = convex_maxlen(n);
		printf("%.2lf\n", ans);
	}
	return 0;
}