题目大意
给出n条直线,表示成y=Ax+B的形式(|A|,|B|<=500000),且n条直线两两不重合.求出所有可见的直线。可见的定义为从y为无穷大的地方往下看可见,既未被其他直线完全覆盖。
题解
把所有的直线按k递增为第一关键字,b递减为第二关键字排序。因为所有可见的直线一定能组成一个类似下凸的形状。
然后逐个压入栈中,压栈之前把这条直线能覆盖的直线都弹出,既只要这条直线与sta[top-1]的交点在sta[top]与sta[top-1]的交点左边,则sta[top]就一定被这条直线覆盖了。
注意处理两直线平行的情况。
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=int(5e4)+1111;
struct Line {
double k,b;
int id;
bool operator < (const Line &B) const {
if(k!=B.k) return k<B.k;
if(b!=B.b) return b>B.b;
return id<B.id;
}
double cross(const Line &B) const {
return (B.b-b)/(k-B.k);
}
}l[maxn],sta[maxn];
int ans[maxn];
int top=0;
int main() {
#ifndef ONLINE_JUDGE
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif // ONLINE_JUDGE
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) {
l[i].id=i;
scanf("%lf%lf",&l[i].k,&l[i].b);
}
sort(l+1,l+1+n);
for(int i=1;i<=n;i++) {
if(l[i].k==l[i-1].k) continue;
if(top<1) {sta[++top]=l[i]; continue;}
while(top>1 && sta[top-1].cross(l[i])<=sta[top-1].cross(sta[top]))
top--;
sta[++top]=l[i];
}
for(int i=1;i<=top;i++) ans[i]=sta[i].id;
sort(ans+1,ans+1+top);
for(int i=1;i<=top;i++) printf("%d ",ans[i]);
printf("\n");
return 0;
}