HNOI 2008 水平可见直线

来源:互联网 发布:女生一开始很热情知乎 编辑:程序博客网 时间:2024/05/29 04:42

                      HNOI 2008 水平可见直线

在 xoy 直角坐标平面上有n条直线 L1,L2,...,Ln,若在y 值为正无穷大处往下看,能见到 Li的某个子线段,则称 Li为可见的,否则 Li为被遮盖的。 
例如,对于直线 
L1:y=x; L2:y=-x; L3:y=0 
则 L1和L2是可见的,L3是被遮盖的。 
给出 n 条直线,表示成 y=Ax+B 的形式(|A|,|B|<=500000),且 n 条直线两两不重合。求出所有可见的直线。

第一行为 n(0<n<50000),接下来 n行输入 Ai,Bi。 

从小到大输出可见直线的编号,两两中间用空格隔开。 


-1 0 
1 0 
0 0

1 2 

n<50000



本题题解三部曲:

一部曲:以k为第一关键字,b为第二关键字,进行排序。

二部曲:构建关于直线的单调栈。

三部曲:整理并输出答案。

就这么简单。


#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;#define N 50000 + 5int n, s[N], t[N];struct LINE{int num;double k, b; void init(int i){scanf("%lf%lf", &k, &b);num = i;}bool operator < (const LINE a) const{return k < a.k || (k == a.k && b > a.b);}}h[N];void begin(){scanf("%d", &n);for (int i = 1; i <= n; i ++)h[i].init(i);sort(h + 1, h + n + 1);}double dotx(LINE u, LINE v){return (u.b - v.b) / (v.k - u.k);}void work(){s[0] = s[1] = 1;for (int i = 2; i <= n; i ++){if (h[i].k == h[i - 1].k) continue;while (s[0] > 1 && dotx(h[s[s[0] - 1]], h[i]) <= dotx(h[s[s[0] - 1]], h[s[s[0]]]))s[0] --;s[++ s[0]] = i;}for (int i = 1; i <= s[0]; i ++)t[i] = h[s[i]].num;sort(t + 1, t + s[0] + 1);}void end(){for (int i = 1; i <= s[0]; i ++)printf("%d ", t[i]);}int main(){begin();work();end();return 0;}


0 0
原创粉丝点击