Description
在
xoy
x
o
y
直角坐标平面上有
n
n
条直线,若在
y
y
值为正无穷大处往下看,能见到的某个子线段,则称
Li
L
i
为
可见的,否则
Li
L
i
为被覆盖的.
例如,对于直线:
L1:y=x;L2:y=−x;L3:y=0
L
1
:
y
=
x
;
L
2
:
y
=
−
x
;
L
3
:
y
=
0
则
L1
L
1
和
L2
L
2
是可见的,
L3
L
3
是被覆盖的.
给出
n
n
条直线,表示成的形式(
|A|,|B|<=500000
|
A
|
,
|
B
|
<=
500000
),且
n
n
条直线两两不重合.求出所有可见的直线.
Input
第一行为,接下来的 N N 行输入
Output
从小到大输出可见直线的编号,两两中间用空格隔开,最后一个数字后面也必须有个空格
Sample Input
3
-1 0
1 0
0 0
Sample Output
1 2
Solution
显然最后可以看见的部分是一个上凸包,组成这些凸包的直线按照斜率从小到大排,相邻两条线交点的横坐标必然递增,故类似求凸包的过程,把直线排完序后,用一个栈维护当前可以看见的直线,对于新加入的直线,求出栈顶直线和栈顶前面的一条直线的交点以及求出新加入直线与栈顶直线的交点横坐标,如果新加入直线与栈顶直线的交点横坐标小于栈中前两条直线的交点横坐标,则说明栈顶直线会被新加入的直线以及栈顶前面一条直线挡住,故栈顶元素出栈,以此一条条将 n n <script type="math/tex" id="MathJax-Element-19">n</script>条直线加入,最后栈内元素即为可见的直线
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=50005;
#define eps 1e-8
int sign(double x)
{
if(fabs(x)<eps)return 0;
if(x>eps)return 1;
return -1;
}
struct node
{
double k,b;
int id;
bool operator<(const node &a)const
{
if(sign(k-a.k)==0)return b<a.b;
else return k<a.k;
}
}p[maxn],s[maxn];
double X(node x,node y)
{
return (y.b-x.b)/(x.k-y.k);
}
int n,vis[maxn];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lf%lf",&p[i].k,&p[i].b);
p[i].id=i;
}
sort(p+1,p+n+1);
int top=0;
for(int i=1;i<=n;i++)
{
while(top)
{
if(sign(p[i].k-s[top].k)==0)top--;
else if(top>1&&sign(X(p[i],s[top-1])-X(s[top],s[top-1]))<=0)top--;
else break;
}
s[++top]=p[i];
}
while(top)vis[s[top--].id]=1;
for(int i=1;i<=n;i++)
if(vis[i])printf("%d ",i);
printf("\n");
return 0;
}