在 x−yx-yx−y 直角座標平面上有 nnn 條直線 L1,L2,…LnL_1,L_2,…L_nL1,L2,…Ln,若在 yyy 值爲正無窮大處往下看,能見到 LiL_iLi 的某個子線段,則稱 LiL_iLi 爲可見的,不然 LiL_iLi 爲被覆蓋的。 例如,對於直線: L1:y=xL_1:y=xL1:y=x; L2:y=−xL_2:y=-xL2:y=−x; L3:y=0L_3:y=0L3:y=0; 則 L1L_1L1 和 L2L_2L2 是可見的,L3L_3L3 是被覆蓋的。給出 nnn 條直線,表示成 y=Ax+By=Ax+By=Ax+B 的形式(∣A∣,∣B∣≤500000|A|,|B| \le 500000∣A∣,∣B∣≤500000),且 nnn 條直線兩兩不重合,求出全部可見的直線。ios
第一行爲 NNN (0<N<500000<N<500000<N<50000),接下來的 NNN 行輸入 Ai,BiA_i,B_iAi,Bi算法
輸出格式:從小到大輸出可見直線的編號,兩兩中間用空格隔開,最後一個數字後面也必須有個空格。spa
3 -1 0 1 0 0 0
1 2
考驗腦洞能力的一個題,首先,相同斜率的兩條線段,bi較低的必定會被較高的覆蓋,而後,把線段按斜率爲第一關鍵字從小到大截距爲第二關鍵字從小到大排序,對於第 i 個線段,若是它與當前沒被覆蓋的第 i - 2 個線段交點的橫座標比第 i - 1 個線段與 i - 2 個線段交點的橫座標要靠左,那麼第 i - 1 個線段必定會被覆蓋(上面被第 i 個線段覆蓋,下面被第 i - 2 個線段覆蓋)。由此能夠得出線性的算法。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<string> 5 #include<queue> 6 using namespace std; 7 const int N = 5e4 + 5; 8 int s[N],top,n,ans[N]; 9 inline void read(int&x) 10 { 11 x = 0;char c;int sign = 1; 12 do{ c = getchar(); if(c == '-') sign = -1; }while(c < '0' || c>'9'); 13 do{ x = x*10 + c -'0';c = getchar(); }while(c <= '9' && c >= '0'); 14 x *= sign; 15 } 16 struct str{ 17 int a,b,id; 18 }a[N]; 19 const bool cmp(str a,str b){ if(a.a != b.a)return a.a >b.a;else return a.b >b.b; } 20 const bool cmop(int a,int b){ return a < b; } 21 double sol(int i,int j){ return (double)(a[i].b - a[j].b)/(double)(a[j].a - a[i].a); } 22 int main() 23 { 24 read(n); 25 for(int i = 1;i <= n;i++) 26 { 27 read(a[i].a);read(a[i].b); 28 a[i].id = i; 29 } 30 sort(a+1,a+1+n,cmp); 31 for(int i = 1;i <= n;i++) 32 { 33 if(a[i].a == a[i-1].a && i != 1) continue; 34 while(top > 1 && sol(s[top],i) >= sol(s[top],s[top - 1])) top--; 35 s[++top] = i; 36 ans[top] = a[i].id; 37 } 38 sort(ans,ans + top + 1,cmop); 39 for(int i = 1;i <= top;i++) printf("%d ",ans[i]); 40 return 0; 41 }