BZOJ 3707: 圈地

分析

黄学长说随机能过,事实上似乎数据加强了emmm
如果我们确定了2个点以后,第三个点有必要去盲目的枚举吗?答案是否定的。实际上我们把经过这两点的线看成一个斜率,把他当成y轴你会发现第三个点明显是在坐标系左右找一个离”y轴”最近的点来算面积更新答案。然后我们可以继续思考,发现我们可以把点按照某个斜率当成”y轴”进行“从左到右”的排序,这样当2点共线的时候,用这两个点的左右2个点去更新答案就好了。也就是说我们采用旋转坐标系的方法,一开始按x坐标排好序,认为直接用竖着的那条斜率,然后维护的话每次其实当两点共线后只要交换他们就能得到斜率转过该事件点的序列。所以我们可以预处理出所有可行的斜率,当成事件点,不断转动坐标系更新答案就好。这样复杂度只有n^2,期望得分100

代码

hzw说这个随机能过,假

#include <bits/stdc++.h>

#define inf 1000000000
#define ll long long

int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    return x * f;
}

int n,block,cnt;
double ans = 1e60;

struct P
{
    double x,y;
}p[1005];

P operator -(P a,P b)
{
    return (P){a.x - b.x, a.y - b.y};
}

double cross(P a,P b)
{
    return a.x * b.y - a.y * b.x;
}

bool operator <(P a,P b)
{
    return a.x < b.x || (a.x == b.x && a.y < b.y);
}

P rotate(P a,double x)
{
    return (P){a.x * cos(x) - a.y * sin(x), a.y * cos(x) + a.x * sin(x)};
}

void cal(int a,int b)
{
    for (int i = a; i <= b - 2; i++)
        for (int j = i + 1; j <= b - 1; j++)
            for (int k = j + 1; k <= b; k++)
                ans = std::min(ans, abs(cross(p[i] - p[k], p[j] - p[k])) / 2.0);
}

void solve()
{
    double t = rand() / 10000;
    for (int i = 1; i <= n; i++)
        p[i] = rotate(p[i],t);
    std::sort(p + 1, p + n + 1);
    for (int i = 1; i <= cnt; i++)
    {
        int t1 = block * (i - 1) + 1, t2 = block * i;
        t2 = std::min(t2,n);
        cal(t1,t2);
    }
}

int main()
{
    n = read();
    srand(time(0));
    block = sqrt(n) + 10;
    cnt = n / block + (n % block != 0);
    for (int i = 1; i <= n; i++)
        p[i].x = read(), p[i].y = read();
    for (int i = 1; i <= 100; i++)
        solve();
    printf("%.2lf",ans);
}
#include <bits/stdc++.h>

using namespace std;

const int mxn = 1005;

int n, m, p;

double ans = 1e200;

struct Pair
{
    double x, y;

    inline Pair(void) {};
    inline Pair(double a, double b)
        : x(a), y(b) {};
}P[mxn];

inline Pair operator - (const Pair &a, const Pair &b)
{
    return Pair(a.x - b.x, a.y - b.y);
}

struct Line
{
    int a, b;
    double k;

    inline void set(int i, int j)
    {
        a = i;
        b = j;

        k = (P[i].y - P[j].y) / (P[i].x - P[j].x);
    }
}L[mxn * mxn];

inline bool cmpP(const Pair &a, const Pair &b)
{
    if (a.x != b.x)
        return a.x < b.x;
    else
        return a.y < b.y;
}

inline bool cmpL(const Line &a, const Line &b)
{
    return a.k < b.k;
}

inline double cross(const Pair &a, const Pair &b)
{
    return a.x * b.y - a.y * b.x;
}

int ps[mxn], rk[mxn];

signed main(void)
{
    cin >> n;

    for (int i = 0; i < n; ++i)
        cin >> P[i].x >> P[i].y;

    sort(P, P + n, cmpP);

    for (int i = 0; i < n; ++i)
        for (int j = 0; j < i; ++j)
            L[m++].set(i, j);

    sort(L, L + m, cmpL);

    for (int i = 0; i < n; ++i)
        rk[i] = ps[i] = i;

    for (int i = 0; i < m; ++i)
    {
        int a = L[i].a, b = L[i].b;

        if (ps[a] > ps[b])swap(a, b);

        if (ps[a] > 1 - 1)ans = min(ans, fabs(cross(P[a] - P[b], P[rk[ps[a] - 1]] - P[b])));
        if (ps[b] < n - 1)ans = min(ans, fabs(cross(P[a] - P[b], P[rk[ps[b] + 1]] - P[a])));

        swap(ps[a], ps[b]), swap(rk[ps[a]], rk[ps[b]]);
    }

    cout << fixed << setprecision(2) << ans / 2.0 << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值