zoukankan      html  css  js  c++  java
  • 「HNOI2008」水平可见直线

    传送门

    半平面交(×)一次函数(√)

    观察一下题面,很显然他是让你维护一个凸壳。

    我们考虑把所有直线按照斜率从小到大排序,相同斜率的取在 (y) 轴上的截距最大的。

    然后我们类似于求凸包地,依次将直线试着加入一个单调栈中,弹出一条直线的条件就是它被挡住了。

    考虑栈顶被挡住的情况:由于我们是按照斜率从小到大加直线的,画一个图不难发现当前直线和栈顶的交点,在栈顶和栈顶下面一个的交点的左边(可以重合),满足条件时就把栈顶弹掉。

    求交点就是解一个二元一次方程组。

    最后留在栈中的就是可以被看见的直线。

    方便起见,可以特判一下去重后 (n = 1) 的情况。

    参考代码:

    #include <algorithm>
    #include <cstdio>
    using namespace std;
    
    const int _ = 5e4 + 5;
    
    int n, now, top, ans[_]; struct node { double k, b; int id; } t[_], stk[_];
    
    int cmp(node x, node y) { return x.k < y.k || (x.k == y.k && x.b > y.b); }
    
    double cross(node x, node y) { return (x.b - y.b) / (y.k - x.k); }
    
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("cpp.in", "r", stdin), freopen("cpp.out", "w", stdout);
    #endif
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i)
            scanf("%lf %lf", &t[i].k, &t[i].b), t[i].id = i;
        sort(t + 1, t + n + 1, cmp);
        t[++now] = t[1];
        for (int i = 2; i <= n; ++i)
            if (t[i].k != t[i - 1].k) t[++now] = t[i];
        if (now == 1) { printf("%d ", t[1].id); return 0; }
        stk[++top] = t[1], stk[++top] = t[2];
        for (int i = 3; i <= now; ++i) {
            while (top >= 2 && cross(t[i], stk[top]) <= cross(stk[top - 1], stk[top])) --top;
            stk[++top] = t[i];
        }
        for (int i = 1; i <= top; ++i) ans[stk[i].id] = 1;
        for (int i = 1; i <= n; ++i) if (ans[i]) printf("%d ", i);
        return 0;
    }
    
  • 相关阅读:
    下划线的学习4
    下划线的学习3
    下划线的学习2
    下划线的学习1
    小程序登录 之 支付宝授权
    开发第一个flutter程序 hello world
    flutter 环境安装以及配置
    地图组件上的自定义区域叠加层显示 ArcGis + GeoJson
    Netty+MUI从零打造一个仿微信的高性能聊天项目,兼容iPhone/iPad/安卓
    linux 下的emoji在MariaDB中的字符集修改
  • 原文地址:https://www.cnblogs.com/zsbzsb/p/13160417.html
Copyright © 2011-2022 走看看