bzoj1038: [ZJOI2008]瞭望塔

半平面交

过点(xi-1,yi-1)到点(xi,yi)作直线,直线上方是可选区域

然后求半平面交

最小高度只可能在所求半平面交的顶点或山的轮廓顶点处取到

用扫描线维护一下就行了

复杂度O(nlogn),不过此题n很小,暴力O(n^2)也能过

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
#define MAXN 303
#define EPS (1e-6)
int dcmp(double a, double b = 0)
{
    if (fabs(a - b) <= EPS)
        return 0;
    return a < b ? -1 : 1;
}
struct Point
{
    double x, y;
    Point(double _x = 0, double _y = 0)
        : x(_x), y(_y) {}
} a[MAXN];
typedef Point Vector;
Vector operator- (const Vector &a, const Vector &b)
{
    return Vector(a.x - b.x, a.y - b.y);
}
double cross(const Vector &a, const Vector &b)
{
    return a.x * b.y - a.y * b.x;
}
bool parallel(const Vector &a, const Vector &b)
{
    return dcmp(a.x * b.y, a.y * b.x) == 0;
}
struct Line
{
    Point p;
    Vector v; // left
    Line() {}
    Line(const Point &_p, const Vector &_v)
        : p(_p), v(_v) {}
    bool operator< (const Line &x)const
    {
        return v.y / v.x < x.v.y / x.v.x;
    }
} l[MAXN], l2[MAXN];
Point intersect(const Line &a, const Line &b)
{
    double y = (a.v.x * a.p.y * b.v.y - a.p.x * b.v.y * a.v.y + b.p.x * b.v.y * a.v.y - b.p.y * b.v.x * a.v.y) / (a.v.x * b.v.y - b.v.x * a.v.y);
    double x;
    if (dcmp(a.v.y))
        x = a.v.x / a.v.y * (y - a.p.y) + a.p.x;
    else
        x = b.v.x / b.v.y * (y - b.p.y) + b.p.x;
    return Point(x, y);
}
int n;
typedef struct ptrbase *ptr;
struct ptrbase
{
    int data;
    ptr next, last;
    ptrbase(int _data, ptr _next = NULL, ptr _last = NULL)
        : data(_data), next(_next), last(_last) {}
};
ptr head, tail;
bool InHalf(const Point &p, const Line &l)
{
    return dcmp(cross(l.v, p - l.p)) >= 0;
}
struct Event
{
    int type; // 0--up 1--down
    int num;
    Event(int _type, int _num)
        : type(_type), num(_num) {}
    bool operator< (const Event &x)const
    {
        double x1 = type ? a[num].x : intersect(l2[num], l2[num + 1]).x;
        double x2 = x.type ? a[x.num].x : intersect(l2[x.num], l2[x.num + 1]).x;
        return x1 < x2;
    }
};
vector<Event> e;
int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; ++i)
        scanf("%lf", &a[i].x);
    for (int i = 0; i < n; ++i)
        scanf("%lf", &a[i].y);
    double mm = a[0].y;
    for (int i = 1; i < n; ++i)
        mm = max(mm, a[i].y);
    for (int i = 1; i < n; ++i)
        l[i - 1] = Line(a[i - 1], a[i] - a[i - 1]);
    sort(l, l + n - 1);
    head = tail = new ptrbase(0);
    for (int i = 1; i < n - 1; ++i)
    {
        if (tail && parallel(l[tail->data].v, l[i].v))
        {
            if (InHalf(l[i].p, l[tail->data]))
            {
                ptr p = tail->last;
                delete tail;
                tail = p;
                if (tail)
                    tail->next = NULL;
                else
                    head = NULL;
            }
            else
                continue;
        }
        while (tail && tail->last)
            if (InHalf(intersect(l[tail->data], l[tail->last->data]), l[i]))
                break;
            else
            {
                tail = tail->last;
                delete tail->next;
                tail->next = NULL;
            }
        while (head && head->next)
            if (InHalf(intersect(l[head->data], l[head->next->data]), l[i]))
                break;
            else
            {
                head = head->next;
                delete head->last;
                head->last = NULL;
            }
        if (head == NULL)
            head = tail = new ptrbase(i);
        else
        {
            tail->next = new ptrbase(i, NULL, tail);
            tail = tail->next;
        }
    }
    int m = 0;
    for (ptr i = head; i; i = i->next)
        l2[m++] = l[i->data];
    for (int i = 0; i < n; ++i)
        e.push_back(Event(1, i));
    for (int i = 0; i < m - 1; ++i)
        e.push_back(Event(0, i));
    sort(e.begin(), e.end());
    double ans = 1e300;
    vector<Event>::iterator s = e.begin();
    while (s != e.end() && s->type == 0)
        ++s;
    vector<Event>::iterator t = e.end();
    while (t != e.begin() && (t - 1)->type == 0)
        --t;
    int i = 0, j = 0; // i--up j--down
    for (vector<Event>::iterator it = e.begin(); it != e.end(); ++it)
    {
        if (it->type == 0)
        {
            if (it >= s && it < t)
            {
                Point p = intersect(l2[i], l2[i + 1]);
                ans = min(ans, p.y - (a[j - 1].y + (p.x - a[j - 1].x) * (a[j].y - a[j - 1].y) / (a[j].x - a[j - 1].x)));
            }
            ++i;
        }
        else
        {
            if (it >= s && it < t)
                ans = min(ans, l2[i].p.y + (a[j].x - l2[i].p.x) * l2[i].v.y / l2[i].v.x - a[j].y);
            ++j;
        }
    }
    printf("%.3lf\n", ans);
    return 0;
}


阅读更多
文章标签: bzoj
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭