半平面交
过点(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;
}