HDU-2297 Run 计算几何 凸包思想
HDU-2297 Run
题意: 一维线段n个可以运动的点,位置为p, 速度为v。 求在运动的过程中有多少点可以领跑(在最前面)。
分析: 可以将速度v也变成一个维度, 一个点要超过另一个点的前提条件是速度更大, 其中可以根据求凸包的思想, 如果这个点到另一个点的相对距离与相对速度做除法运算, 即求得斜率。 斜率大的可以更先跑到前面并且不会被他超过, 在这里要对位置和速度排序, 然后按照求凸包的思想直接求解。 关于一个点可以在超过最前面的点超过另一个点解释见下图。绿色和蓝色分别代表斜率。
代码:
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
int sgn(double x)
{
if (fabs(x) < eps)
return 0;
else if (x < 0)
return -1;
else
return 1;
}
struct Point
{
double p, v;
Point() {}
Point(double _p, double _v)
{
p = _p;
v = _v;
}
bool operator<(const Point b) const
{
if (sgn(p - b.p) == 0)
return sgn(v - b.v) < 0;
else
return sgn(p - b.p) > 0;
}
};
const int MAXN = 1e5 + 10;
Point p[MAXN], st[MAXN];
int n;
bool check(Point p0, Point a, Point b)
{
double area = (b.p - a.p) * (p0.v - a.v) - (a.p - p0.p) * (a.v - b.v);
return sgn(area) >= 0;
}
int solve()
{
int top = 1;
sort(p, p + n);
double mv = p[0].v;
st[0] = Point(p[0].p, 0);
st[1] = p[0];
//st[top++] = p[0];
for (int i = 1; i < n; i++)
{
if (p[i].v < mv)
continue;
while (top > 0 && check(p[i], st[top], st[top - 1]))
top--;
st[++top] = p[i];
mv = p[i].v;
}
return top;
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%lf%lf", &p[i].p, &p[i].v);
printf("%d\n", solve());
}
return 0;
}