[BZOJ1007][HNOI2008]水平可见直线(栈)

来源:互联网 发布:免费扫描软件 编辑:程序博客网 时间:2024/06/01 16:01

首先,将所有的直线按照斜率(A) 从小到大排序,相同情况按照B从小到大排序,这样,A相同的直线中只有B最大的才可见。这样先去除掉一些一定被覆盖的直线,使每条直线的A都不同。
如果合法直线只有不到3条,那么所有的合法直线都可见。
否则建立一个栈,把前2条直线加入栈中,这2条直线在其他的直线被加入之前全部可见。
考虑加入一条新的直线。加入一条新的直线之后,在这之前栈中的直线(可见)有可能被覆盖,但由于已经按A排序,所以如果栈中的一条直线l1在加入了这条直线l2之后被覆盖,那么栈中l1之后的直线(除l2外)必然被覆盖。因此在加入l2之前,应该:
(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;}
阅读全文
0 0
原创粉丝点击