2020杭电多校6,HDU- 6830- Asteroid in Love (几何,凸包)

2020杭电多校6,HDU- 6830- Asteroid in Love (几何,凸包)

Problem Description

During the summer vacation, the geoscience community launched a constellation observation activity.

On a clear night, Mira and Ao set up their telescopes. Through the telescopes, they observed n stars. These n stars could be regarded as points on a two-dimensional plane, with coordinates (xi,yi).

It was boring to observe the stars alone, so they classified these stars into three categories according to their spectrum: R-type stars, G-type stars, and B-type stars.

Now, Mira wants to form a constellation named after Ao, for Ao to make up for the regret that there is no star named after Ao. This constellation should be small and beautiful. She wants the number of stars to be the least in this constellation. Besides, she wants the constellation contains all types of stars. It is easy to know that this constellation has only three stars, and the types of these three stars are R type, G type, and B type.

She also wants the area of the convex polygon enclosed by the stars of this constellation is the largest, that is, the area of the triangle formed by these three stars is the largest. If the triangle is trivial (that is, the three points that make up the triangle are on the same straight line), the area of the triangle is considered to be 0.

Please tell Mira the largest area of Constellation Ao.

题意:

给定\(\mathit n\) 个分为\(\text 3\)类的二维平面上的点,每一类至少有一个点,现在让你从三类中各选择出一个节点,使其三个节点构成的三角形面积最大。求最大的面积值,其中\(n\leq 3\times 10^3\)

思路:

很容易想到的是枚举两个类中的节点,然后再第三个类中找一个节点,使其与前两点构成的直线距离最远。

假设我们枚举的是分别属于类\(0,1\)中的两个节点\(A,B\)那么属于类\(\text 2\) 的点\(\mathit C\)一定属于类\(\text 2\) 中所有点构成的凸包中。

因为若不在凸包中,一定可以有一个在凸包中的点使其与直线\((A,B)\)距离更远。

所以现在问题转化为了,在一个凸包中找到一个点与给定直线距离最大,我们来观察下图:

我们用Andrew算法求凸包的适合,将其分成两部分,即上轮廓和下轮廓。

通过分析我们可以发现,无论枚举的线段和凸包的位置关系是什么,上轮廓和下轮廓中的点到线段的距离都是一个单峰函数。

例如上图中,点\(H,G,F,E,D\)(下轮廓)和线段\((K,L)\)是开口向上的单峰函数。

\(A,B,C,D\)(上轮廓)和线段\((K,L)\)是开口向下的单峰函数。

而对于线段\((I,J)\)开口恰好相反,我们又不方便确定距离函数的开口方向,那么我们不妨将2种情况都考虑进去(即凸函数和凹函数),分别求出它们的极值,答案一定会被考虑进去。

对于一个单峰函数求极值问题,我们知道三分算法可以轻易的解决。

注意:一定要把凸包分成两个凹凸相反的部分,这样才能保证是单峰函数。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <bits/stdc++.h>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define chu(x)  if(DEBUG_Switch) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
ll poww(ll a, ll b) { if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a ;} a = a * a ; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
void pvarr_int(int *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%d%c", arr[i], i == n ? '\n' : ' ');}}
void pvarr_LL(ll *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%lld%c", arr[i], i == n ? '\n' : ' ');}}
const int maxn = 3010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
#define DEBUG_Switch 0
const double pi = acos(-1);

struct Point
{
    ll x, y;
    Point() {}
    Point(ll _x, ll _y)
    {
        x = _x; y = _y;
    }
    Point operator -(const Point &b)const
    {
        return Point(x - b.x, y - b.y);
    }
    //??
    ll operator ^(const Point &b)const
    {
        return x * b.y - y * b.x;
    }
};
Point base;
inline bool cmp(const Point& a, const  Point& b)
{
    if (a.x != b.x)
        return a.x < b.x;
    else
        return a.y < b.y;
    // double A = atan2((a.y - base.y), (a.x - base.x));
    // double B = atan2((b.y - base.y), (b.x - base.x));
    // if (A != B)return A < B;
    // else    return a.x < b.x;
}
long long Cross(Point a, Point b, Point c)
{
    return 1LL * (b.x - a.x) * (c.y - a.y) - 1LL * (b.y - a.y) * (c.x - a.x);
}
void Get(int n, Point *p , Point * S, int &top, int op)
{
    sort(&p[1], &p[n + 1], cmp);
    top = 0;
    if (op)
        for (int i = 1; i <= n;)
        {
            while (top > 1 && Cross(S[top - 1], p[i], S[top]) >= 0)
                top--;
            S[++top] = p[i++];
        }
    else
        for (int i = n; i >= 1;)
        {
            while (top > 1 && Cross(S[top - 1], p[i], S[top]) >= 0)
                top--;
            S[++top] = p[i--];
        }
}
int n;
Point p[3][maxn];
int cnt[3];
Point S1[maxn], S2[maxn];
int top1, top2;
ll solve(Point a, Point b)
{
    ll h = 0ll;
    int l, r;
    l = 1;
    r = top1;
    while (r - l >= 3)
    {
        int lmid = (l + l + r) / 3;
        int rmid = (l + r + r) / 3;
        if (abs((a - b) ^ (a - S1[lmid])) > abs((a - b) ^ (a - S1[rmid])) )
        {
            r = rmid;
        } else
        {
            l = lmid;
        }
    }
    repd(i, l, r)
    {
        h = max(h, abs((a - b) ^ (a - S1[i])));
    }
    l = 1;
    r = top1;
    while (r - l >= 3)
    {
        int lmid = (l + l + r) / 3;
        int rmid = (l + r + r) / 3;
        if (abs((a - b) ^ (a - S1[lmid])) < abs((a - b) ^ (a - S1[rmid])) )
        {
            r = rmid;
        } else
        {
            l = lmid;
        }
    }
    repd(i, l, r)
    {
        h = max(h, abs((a - b) ^ (a - S1[i])));
    }
    l = 1;
    r = top2;
    while (r - l >= 3)
    {
        int lmid = (l + l + r) / 3;
        int rmid = (l + r + r) / 3;
        if (abs((a - b) ^ (a - S2[lmid])) > abs((a - b) ^ (a - S2[rmid])) )
        {
            r = rmid;
        } else
        {
            l = lmid;
        }
    }
    repd(i, l, r)
    {
        h = max(h, abs((a - b) ^ (a - S2[i])));
    }
    l = 1;
    r = top2;
    while (r - l >= 3)
    {
        int lmid = (l + l + r) / 3;
        int rmid = (l + r + r) / 3;
        if (abs((a - b) ^ (a - S2[lmid])) < abs((a - b) ^ (a - S2[rmid])) )
        {
            r = rmid;
        } else
        {
            l = lmid;
        }
    }
    repd(i, l, r)
    {
        h = max(h, abs((a - b) ^ (a - S2[i])));
    }
    return h;
}
int main()
{
#if DEBUG_Switch
    freopen("C:\\code\\input.txt", "r", stdin);
#endif
    //freopen("C:\\code\\output.txt","w",stdout);
    int t;
    t = readint();
    while (t--)
    {
        cnt[0] = cnt[1] = cnt[2] = 0;
        n = readint();
        Point temp;
        repd(i, 1, n)
        {
            temp.x = readint();
            temp.y = readint();
            int tp = readint();
            cnt[tp]++;
            p[tp][cnt[tp]] = temp;
        }
        Get(cnt[0], p[0], S1, top1, 1);
        Get(cnt[0], p[0], S2, top2, 0);
        ll ans = 0ll;
        repd(i, 1, cnt[1])
        {
            repd(j, 1, cnt[2])
            {
                ans = max(ans, solve(p[1][i], p[2][j]));
            }
        }
        if (ans & 1)
        {
            printf("%lld.5\n", ans / 2 );
        } else
        {
            printf("%lld.0\n", ans / 2 );
        }
    }

    return 0;
}

posted @ 2020-08-07 21:35  茄子Min  阅读(331)  评论(0编辑  收藏  举报