1007: [HNOI2008]水平可见直线
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 6200 Solved: 2351
[ Submit][ Status][ Discuss]
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
关键是:并不是交点不能共线,而是排序后的射线不能有两个交点重合,如果有,那么删掉中间的射线。
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define all(x) (x).begin(), (x).end()
#define for0(a, n) for (int (a) = 0; (a) < (n); (a)++)
#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)
#define mes(a,x,s) memset(a,x,(s)*sizeof a[0])
#define mem(a,x) memset(a,x,sizeof a)
#define ysk(x) (1<<(x))
#define sqr(x) ((x)*(x))
typedef long long ll;
typedef pair<int, int> pii;
const int INF =0x3f3f3f3f;
const int inf =1e25;
const int maxn=50000 ;
int n;
const double PI=cos(-1.0);
const double eps=1e-10;
int dcmp(double x)
{
if(fabs(x)<eps) return 0;
else return x<0?-1:1;
}
struct Point
{
double x,y;
Point(double x=0,double y=0):x(x),y(y) {};
bool operator ==(const Point B)const {return dcmp(x-B.x)==0&&dcmp(y-B.y)==0;}
bool operator<(const Point& b)const
{
return dcmp(x-b.x)<0|| dcmp(x-b.x)==0 &&dcmp(y-b.y)<0;
}
}poly[maxn+10];
typedef Point Vector;
Vector operator -(Vector A,Vector B) {return Vector(A.x-B.x,A.y-B.y); }
double Cross(Vector A,Vector B)//叉乘
{
return A.x*B.y-A.y*B.x;
}
double Dot(Vector A,Vector B)//点乘
{
return A.x*B.x+A.y*B.y;
}
Vector operator +(Vector A,Vector B) {return Vector(A.x+B.x,A.y+B.y); }
Vector operator *(Vector A,double p) {return Vector(A.x*p,A.y*p); }
Point GetLineIntersection(Point P,Vector v,Point Q,Vector w)//点线式
{
Vector u=P-Q;
double t=Cross(w,u)/Cross(v,w);
return P+v*t;
}
struct Line
{
Point p,p2;
Vector v;
double ang;
int ind;
Line(){}
Line(Point a,Vector v):p(a),v(v){ang=atan2(v.y,v.x); }//点线式
void twoPointIntial(Point p,Point p2)//两点式
{
this->p=p;
this->p2=p2;
v= p2-p;
ang=atan2(v.y,v.x);
}
Point point(double t)//参数方程求参数t对应点
{
return p+v*t;
}
bool operator<(const Line & L)const
{
return ang<L.ang;
}
void show()
{
cout<<p.x<<" "<<p.y<<" "<<v.x<<" "<<v.y<<endl;
}
}L[maxn+10];
typedef Line Seg;
Point GetIntersection(Line a,Line b)
{
Vector u=a.p-b.p;
double t=Cross(b.v,u)/Cross(a.v,b.v);
return a.p+a.v*t;
}
bool OnRight(Line L,Point p)
{
return dcmp(Cross(L.v,p-L.p))<0;
}
double dis(Point A,Point B)
{
return sqrt(sqr(A.x-B.x)+sqr(A.y-B.y));
}
void HalfplaneIntersection(Line* L,int n,Point * poly)
{
sort(L,L+n);
int first,last;
Point *p=new Point[n];
Line *q=new Line[n];
q[first=last=0]=L[0];
for(int i=1;i<n;i++)
{
while(first<last&&OnRight(L[i],p[last-1] ) ) last--;
while(first<last&&dis(GetIntersection(q[last],L[i]),p[last-1] )<eps ) last--;
while(first<last&&OnRight(L[i],p[first])) first++;
q[++last]=L[i];
if(fabs(Cross(q[last].v,q[last-1].v) )<eps )
{
last--;
if(!OnRight(q[last],L[i].p) ) q[last]=L[i];
}
if(first<last) p[last-1]=GetIntersection(q[last-1],q[last] );
}
while(first<last&&OnRight(q[first],p[last-1])) last--;
// if(last-first<=1) return 0;//小于等于3个,不存在
p[last]=GetIntersection(q[last],q[first]);
vector<int >ans;
for(int i=first;i<=last;i++)
{
ans.push_back(q[i].ind );
}
sort(all(ans));
for0(i,ans.size())
{
printf("%d ",ans[i]);
}
putchar('\n');
}
int main()
{
std::ios::sync_with_stdio(false);
double k,b;
while(cin>>n)
{
for0(i,n)
{
cin>>k>>b;
L[i]= Line(Point(0,b) ,Vector(1,k));
L[i].ind=i+1;
}
HalfplaneIntersection(L,n,poly);
}
return 0;
}