HDU-2297 Run 計算幾何 凸包思想
阿新 • • 發佈:2018-11-26
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;
}