[HNOI2008]水平可见直线
题目描述
在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:
复制
3 -1 0 1 0 0 0
输出样例#1: 复制
1 2
实际上就是求一个最长下凸包
没有学过计蒜几何也没关系,可以自己画图理解
按斜率从小到大排序
实际上考虑两种情况:
1.
这种情况显然可以,就是一个下凸包
2.
这样显然斜率第2的直线无法看到
这样我们可以发现
如果i>j>k
交点(i,k)在交点(j,k)左边,那么j就不行
于是用单调栈
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 struct Node 8 { 9 double a,b; 10 int n; 11 }a[50001]; 12 int n,top,s[50001]; 13 double p1,p2,eps=1e-8; 14 double cross(int i,int j) 15 { 16 double x=(a[j].b-a[i].b)/(a[i].a-a[j].a); 17 return x; 18 } 19 bool cmp(Node a,Node b) 20 { 21 if (fabs(a.a-b.a)<eps) return a.b<b.b; 22 return a.a<b.a; 23 } 24 int main() 25 {int i,j; 26 cin>>n; 27 for (i=1;i<=n;i++) 28 { 29 scanf("%lf%lf",&a[i].a,&a[i].b); 30 a[i].n=i; 31 } 32 sort(a+1,a+n+1,cmp); 33 for (i=1;i<=n;i++) 34 { 35 while (top) 36 { 37 if (fabs(a[i].a-a[s[top]].a)<eps) top--; 38 else if (top>1&&cross(i,s[top-1])<=cross(s[top-1],s[top])) top--; 39 else break; 40 } 41 s[++top]=i; 42 } 43 for (i=1;i<=top;i++) 44 s[i]=a[s[i]].n; 45 sort(s+1,s+top+1); 46 for (i=1;i<=top;i++) 47 printf("%d ",s[i]); 48 }