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 0
1 0
0 0
-1 0
1 0
0 0
Sample Output
1 2
题解:
首先,我们可以按照k的大小(就是y=kx+b)将每条线进行排序。
假设栈中已有n条线,那么在加入下一条线之前进行判断(及维护栈)。
先取栈前两个线,假设其与栈顶的线交于x1,与第二个线交于x2,那么如果x2<=x1,则加入该线后,栈顶的线会被挡住(具体可以画图),那么出栈,然后重复,直到x2>x1.
重复完后将该线入栈。
code:
#include<cstdio>#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
struct aaa{
int k,b,id;
}s[50010],a[50010];
bool cmp1(aaa a1,aaa a2){
return a1.k>a2.k;
}
bool cmp2(int a1,int a2){
return a[a1].id<a[a2].id;
}
int n,_stack[50010];
double getx(int id1,int id2);
int main()
{
cin>>n;
for(int i=1;i<=n;i++){
cin>>s[i].k>>s[i].b;
s[i].id=i;
}
sort(s+1,s+1+n,cmp1);
int num=1;
a[num]=s[num];
for(int i=2;i<=n;i++){
if(s[i].k<a[num].k){
a[++num]=s[i];
continue;
}
if(s[i].b>a[num].b)a[num].b=s[i].b,a[num].id=s[i].id;
}
int _top=1;
_stack[_top]=1;
for(int i=2;i<=num;i++){
while(_top>=2){
double x1=getx(i,_stack[_top-1]),x2=getx(i,_stack[_top]);
if(x1<=x2)_top--;
else break;
}
_stack[++_top]=i;
}
sort(_stack+1,_stack+1+_top,cmp2);
for(int i=1;i<=_top;i++){
cout<<a[_stack[i]].id<<" ";
}
return 0;
}
double getx(int id1,int id2)
{
return (a[id1].b-a[id2].b+0.0)/(a[id2].k-a[id1].k+0.0);
}