1. 程式人生 > >bzoj1007[HNOI2008]水平可見直線

bzoj1007[HNOI2008]水平可見直線

ons open esc pac get code esp 編號 def

Description

  在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條直線兩兩不重合.求出所有可見的直線.

Input

  第一行為N(0 < N < 50000),接下來的N行輸入Ai,Bi

Output

  從小到大輸出可見直線的編號,兩兩中間用空格隔開,最後一個數字後面也必須有個空格

Sample Input

3
-1 0
1 0
0 0

Sample Output

1 2

可以想象最終在上面的圖形是一個半凸包
所以只需要按照斜率排序
將前面的直線都推到一個棧裏
如果新加入的直線和棧頂直線交點在之前交點的左面
那麽凸包棧頂的直線就被覆蓋了,彈出就可以了

技術分享圖片
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define LL long long
 6 
 7 using namespace std;
 8 
 9 const
int MAXN = 5e4 + 10; 10 11 int N; 12 int top = 0; 13 int ans[MAXN]; 14 int sta[MAXN]; 15 double x[MAXN]; 16 17 struct line { 18 double k; 19 double b; 20 int id; 21 } l[MAXN]; 22 23 bool cmp(line a, line b) 24 { 25 if(a.k == b.k) { 26 return a.b > b.b; 27 } 28 return
a.k < b.k; 29 } 30 31 inline LL read() 32 { 33 LL x = 0, w = 1; char ch = 0; 34 while(ch < 0 || ch > 9) { 35 if(ch == -) { 36 w = -1; 37 } 38 ch = getchar(); 39 } 40 while(ch >= 0 && ch <= 9) { 41 x = x * 10 + ch - 0; 42 ch = getchar(); 43 } 44 return x * w; 45 } 46 47 double intersaction(int a, int b) 48 { 49 return (l[b].b - l[a].b) / (l[a].k - l[b].k); 50 } 51 int main() 52 { 53 N = read(); 54 for(int i = 1; i <= N; i++) { 55 scanf("%lf%lf", &l[i].k, &l[i].b); 56 l[i].id = i; 57 } 58 sort(l + 1, l + N + 1, cmp); 59 sta[0] = 1; 60 top = 1; 61 for(int i = 2; i <= N; i++) { 62 if(l[i].k == l[sta[top - 1]].k) { 63 continue; 64 } 65 while(intersaction(i, sta[top - 1]) <= intersaction(sta[top - 1], sta[top - 2]) && top > 1) { 66 top--; 67 } 68 top++; 69 sta[top - 1] = i; 70 } 71 for(int i = 0; i < top; i++) { 72 ans[l[sta[i]].id] = 1; 73 } 74 for(int i = 1; i <= N; i++) { 75 if(ans[i]) { 76 printf("%d ", i); 77 } 78 } 79 return 0; 80 }
View Code

bzoj1007[HNOI2008]水平可見直線