首先,将所有的直线按照斜率(
A
) 从小到大排序,相同情况按照
如果合法直线只有不到
否则建立一个栈,把前
2
条直线加入栈中,这
考虑加入一条新的直线。加入一条新的直线之后,在这之前栈中的直线(可见)有可能被覆盖,但由于已经按
A
排序,所以如果栈中的一条直线
(1)判断栈顶直线是否会在加入
l2
之后被覆盖,如果有则转(2),否则将
l2
加入栈中;
(2)将栈顶元素退栈,转(1)。
操作完成后,栈中剩余的直线就是答案。
p.s.此题可以为凸包、半平面交及斜率优化做一个理解。
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 5e4 + 5; const double eps = 1e-8;
int n; struct cyx {
int k, b, id;
} a[N], b[N]; int top, stk[N];
bool vis[N];
bool comp(cyx a, cyx b) {
if (a.k != b.k) return a.k < b.k;
return a.b < b.b;
}
bool slope(int p1, int p2, int p3) {
double x1 = 1.0 * (a[p2].b - a[p1].b) / (a[p1].k - a[p2].k),
x2 = 1.0 * (a[p3].b - a[p2].b) / (a[p2].k - a[p3].k);
return abs(x1 - x2) <= eps || x1 > x2;
}
int main() {
int i, tn, m = 0; tn = n = read();
for (i = 1; i <= n; i++) a[i].k = read(), a[i].b = read(), a[i].id = i;
sort(a + 1, a + n + 1, comp); for (i = 1; i <= n; i++)
if (i == n || a[i].k != a[i + 1].k) b[++m] = a[i];
n = m; for (i = 1; i <= n; i++) a[i] = b[i];
if (n < 3) {
for (i = 1; i <= n; i++) vis[a[i].id] = 1;
for (i = 1; i <= tn; i++) if (vis[i]) printf("%d ", i);
printf("\n"); return 0;
}
stk[1] = 1; stk[top = 2] = 2; for (i = 3; i <= n; i++) {
while (top > 1 && slope(stk[top - 1], stk[top], i)) top--;
stk[++top] = i;
}
for (i = 1; i <= top; i++) vis[a[stk[i]].id] = 1;
for (i = 1; i <= tn; i++) if (vis[i]) printf("%d ", i);
cout << endl;
return 0;
}