標籤:
1007: [HNOI2008]水平可見直線
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 4567 Solved: 1686
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 01 00 0
Sample Output
1 2
題解:
第一眼我覺得這是一個半平面交,然而仔細看題後發現其實沒那麼複雜,只需要維護一個下凸殼就好了。
Code:
#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>#include<algorithm>using namespace std;#define N 50100struct E{ int xu,a,b;}e[N],ee[N];int n,top=0,num=0,z[N];int in(){ int x=0; char ch=getchar(); bool f=true; while (ch<‘0‘ || ch>‘9‘){ if (ch==‘-‘) f=false; ch=getchar(); } while (ch>=‘0‘ && ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar(); if (!f) x=-x; return x;}bool cmp1(E x,E y){ return x.a>y.a;}bool cmp2(int x,int y){ return ee[x].xu<ee[y].xu;}double jiao(E x,E y){ return (double)((double)(y.b-x.b)/(double)(x.a-y.a));}int main(){ n=in(); z[++top]=1; for (int i=1; i<=n; i++) e[i].xu=i,e[i].a=in(),e[i].b=in(); sort(e+1,e+n+1,cmp1); for (int i=1; i<=n; i++){ if (e[i].a!=ee[i-1].a) ee[++num]=e[i]; else if (e[i].b>ee[num].b) ee[num]=e[i]; } for (int i=2; i<=num; i++){ while (top>=2){ double x1=jiao(ee[z[top-1]],ee[i]); double x2=jiao(ee[z[top]],ee[i]); if (x1<=x2+1e-6) top--; else break; } z[++top]=i; } sort(z+1,z+top+1,cmp2); for (int i=1; i<=top; i++) printf("%d ",ee[z[i]].xu); return 0;}
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
【凸殼】【HNOI 2008】【bzoj 1007】水平可見直線