hdu2202:最大三角形(凸包旋轉卡殼求最大三角形面積)
阿新 • • 發佈:2018-12-13
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; }