POJ2079 && BZOJ1069

一堆点中选三个点构成最大三角形。对于一个构成的三角形,过三角形顶点作与它的底边平行的线,要找面积最大的三角形,即最大的高,则顶点势必在点集构成的凸包上,所以从点集中选出构成面积最大的三角形的三个点一定来自点集构成的凸包。

#include <stack>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 80000 + 5;
const double PI = acos(-1.0);

struct Point{
    double x, y;
    bool extreme;
    int pos;
};
Point P[maxn];

int n;
Point TB[maxn];
int cntTB;

double dis(Point A, Point B){
    return sqrt((A.x - B.x)*(A.x - B.x) + (A.y - B.y)*(A.y - B.y));
}

double cross(Point O, Point A, Point B){
    return (A.x - O.x)*(B.y - O.y) - (A.y - O.y)*(B.x - O.x);
}

bool cmp(Point A, Point B)
{
    int cur = 0;
    double temp = cross(P[cur], A, B);
    if(temp > 0) return true;
    else if(temp == 0 && (dis(P[cur], A) < dis(P[cur], B))) return true;
    else return false;
}

bool ToLeft(Point O, Point A, Point B)
{
    double temp = cross(O, A, B);
    if(temp > 0) return true;
    else if(temp == 0 && (dis(O, A) < dis(O, B))) return true;
    else return false;
}

void Graham()
{
    sort(P+1, P+n, cmp);
    stack<Point> s1, s2;
    while(!s1.empty()) s1.pop();
    while(!s2.empty()) s2.pop();
    if(n == 1){
        s1.push(P[0]);
    }
    else if(n == 2){
        s1.push(P[0]);
        s1.push(P[1]);
    }
    else{
        s1.push(P[0]), s1.push(P[1]);
        for(int i = n-1; i >=2; i--) s2.push(P[i]);

        while(!s2.empty()){
            Point B = s1.top();s1.pop();
            Point A = s1.top();
            Point C = s2.top();
            if(ToLeft(A, B, C)){
                s2.pop();
                s1.push(B), s1.push(C);
            }
        }
    }
    Point a[maxn];
    int cnta = 0;
    while(!s1.empty()){
        a[cnta++] = s1.top();
        s1.pop();
    }
    for(int i = cnta-1; i >= 0; i--) TB[cntTB++] = a[i];
}

double rotat(Point ch[], int n)
{
    double res = 0;
    int i, j, k;
    j = 1; k = 2;
    for(i=0; i<n; i++)
    {
        while((cross(ch[i], ch[j], ch[k]) < cross(ch[i], ch[j], ch[(k+1)%n]))
              ||(cross(ch[i], ch[j], ch[k]) < cross(ch[i], ch[(j+1)%n], ch[k]))){
            while(cross(ch[i], ch[j], ch[k]) < cross(ch[i], ch[j], ch[(k+1)%n]))
                k = (k+1) % n;
            while(cross(ch[i], ch[j], ch[k]) < cross(ch[i], ch[(j+1)%n], ch[k]))
                j = (j+1) % n;
        }
        res = max(res, cross(ch[i], ch[j], ch[k])/2.0);
    }
    return res;
}

int main()
{
    //freopen("1.in", "r", stdin);
    while(scanf("%d", &n)!= EOF && n != -1){
        int tmp = 0;
        cntTB = 0;
        for(int i = 0; i < n; i++){
            scanf("%lf%lf", &P[i].x, &P[i].y);
            P[i].pos = i;
            P[i].extreme = false;
            if(P[i].y < P[tmp].y || (P[i].y == P[tmp].y && P[i].x < P[tmp].x))
                tmp = i;
        }
        swap(P[tmp], P[0]);
        Graham();
        printf("%.2f\n",rotat(TB, cntTB));
    }
    return 0;
}

枚举对角线,旋转两个三角形求最大面积和

#include <stack>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 100000 + 5;
const double PI = acos(-1.0);

struct Point{
    double x, y;
    bool extreme;
    int pos;
};
Point P[maxn], a[maxn];
int n;
Point TB[maxn];
int cntTB;

double dis(Point A, Point B){
    return sqrt((A.x - B.x)*(A.x - B.x) + (A.y - B.y)*(A.y - B.y));
}

double cross(Point O, Point A, Point B){
    return (A.x - O.x)*(B.y - O.y) - (A.y - O.y)*(B.x - O.x);
}

bool cmp(Point A, Point B)
{
    int cur = 0;
    double temp = cross(P[cur], A, B);
    if(temp > 0) return true;
    else if(temp == 0 && (dis(P[cur], A) < dis(P[cur], B))) return true;
    else return false;
}

bool ToLeft(Point O, Point A, Point B)
{
    double temp = cross(O, A, B);
    if(temp > 0) return true;
    else if(temp == 0 && (dis(O, A) < dis(O, B))) return true;
    else return false;
}

void Graham()
{
    sort(P+1, P+n, cmp);
    stack<Point> s1, s2;
    if(n == 1)s1.push(P[0]);
    else if(n == 2){
        s1.push(P[0]);s1.push(P[1]);
    }
    else{
        s1.push(P[0]), s1.push(P[1]);
        for(int i = n-1; i >=2; i--) s2.push(P[i]);
        while(!s2.empty()){
            Point B = s1.top();s1.pop();
            Point A = s1.top();Point C = s2.top();
            if(ToLeft(A, B, C)){
                s2.pop();s1.push(B), s1.push(C);
            }
        }
    }
    int cnta = 0;
    while(!s1.empty()){
        a[cnta++] = s1.top();s1.pop();
    }
    for(int i = cnta-1; i >= 0; i--) TB[cntTB++] = a[i];
}

double rotating_calipers(Point ch[], int n)
{
    double res = 0;
    int k, l;

    for(int i = 0; i < n; i++){
        k = 0, l = 0;
        for(int j = i+1; j < n; j++){
            while(cross(ch[i], ch[j], ch[k]) < cross(ch[i], ch[j], ch[(k+1)%n]))
                k = (k + 1)%n;
            while(cross(ch[j], ch[i], ch[l]) < cross(ch[j], ch[i], ch[(l+1)%n]))
                l = (l + 1)%n;
            res = max(res, cross(ch[i], ch[j], ch[k])*0.5+cross(ch[j], ch[i], ch[l])*0.5);
        }
    }
    return res;
}

int main()
{
    //freopen("1.in", "r", stdin);
    while(scanf("%d", &n)!= EOF && n != -1){
        int tmp = 0;
        cntTB = 0;
        for(int i = 0; i < n; i++){
            scanf("%lf%lf", &P[i].x, &P[i].y);
            P[i].pos = i;
            P[i].extreme = false;
            if(P[i].y < P[tmp].y || (P[i].y == P[tmp].y && P[i].x < P[tmp].x))
                tmp = i;
        }
        swap(P[tmp], P[0]);
        Graham();
        printf("%.3f\n",rotating_calipers(TB, cntTB));
    }
    return 0;
}
posted @ 2017-07-10 22:18  />.<\  阅读(113)  评论(0编辑  收藏  举报