水平可見直線 (1s 128M) lines
【問題描述】
在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
【輸出格式】
從小到大輸出可見直線的編號,兩兩中間用空格隔開,最後一個數字後面也必須有個空格
【樣例輸入】
3
-1 0
1 0
0 0
【樣例輸出】
1 2
題解:
主要算法:計算幾何;快速排序;單調棧;
1.對於斜率相同的兩條直線截距小的被覆蓋。
2.對於斜率不同的三條直線,如果一條直線不可見
那麼必定是斜率最大和斜率最小的覆蓋另外一條線段
同時斜率最大和斜率最小的直線的交點在另一條線段的上方
根據這個性質,通過排序和單調棧即可維護可見直線。
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cstdio> 6 #include<cmath> 7 using namespace std; 8 inline int Get() 9 { 10 int x = 0, s = 1; 11 char c = getchar(); 12 while('0' > c || c > '9') 13 { 14 if(c == '-') s = -1; 15 c = getchar(); 16 } 17 while('0' <= c && c <= '9') 18 { 19 x = (x << 3) + (x << 1) + c - '0'; 20 c = getchar(); 21 } 22 return x * s; 23 } 24 int n; 25 struct shape 26 { 27 int a, b, i; 28 }; 29 shape a[100233]; 30 int s[100233]; 31 int ans[100233]; 32 inline bool rule(shape a, shape b) 33 { 34 if(a.a != b.a) return a.a > b.a; 35 return a.b > b.b; 36 } 37 inline double Sol(int x, int y) 38 { 39 return (double) (a[y].b - a[x].b) / (double) (a[x].a - a[y].a); 40 } 41 int main() 42 { 43 n = Get(); 44 for(int i = 1; i <= n; ++i) 45 { 46 a[i].a = Get(); 47 a[i].b = Get(); 48 a[i].i = i; 49 } 50 sort(a + 1, a + 1 + n, rule); 51 int top = 0; 52 for(int i = 1; i <= n; ++i) 53 { 54 if(a[i].a == a[s[top]].a) continue; 55 while(top > 1 && Sol(s[top], i) >= Sol(s[top], s[top - 1])) 56 --top; 57 s[++top] = i; 58 ans[top] = a[i].i; 59 } 60 sort(ans + 1, ans + 1 + top); 61 for(int i = 1; i <= top; ++i) printf("%d ", ans[i]); 62 }