#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<set>
#include<algorithm>
#define inf 0x7fffffff
#define exp 1e-10
#define PI 3.141592654
using namespace std;
const int MAXN=31110;
struct Point
{
double x,y;
double ang;
int id;
bool st_ed;
Point (double x=0,double y=0):x(x),y(y){ ang=atan2(y,x); }
};
typedef Point Vector;
struct Line
{
Point p;
Vector v;
double ang;
int id;
Line (){}
Line (Point p,Vector v):p(p),v(v){ang=atan2(v.y,v.x); }
}seg[MAXN],now;
Vector operator + (Vector A,Vector B) {return Vector(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); }
Vector operator / (Vector A,double p) {return Vector(A.x/p , A.y/p); }
int dcmp(double x) {if (fabs(x)<exp) return 0;return x>0 ? 1 : -1; }
double cross(Vector A,Vector B)
{
return A.x*B.y-B.x*A.y;
}
bool OnLeft(Line L,Point p)
{
return cross(L.v,p-L.p)>=0;///点P在有向直线L的左边(>=0说明在线上也算)
}
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 operator < (Line A,Line B){
Point PA=GetIntersection(A,now);
Point PB=GetIntersection(B,now);
return (PA.x*PA.x)+(PA.y*PA.y)<(PB.x*PB.x)+(PB.y*PB.y);
}
bool cmp(Point A,Point B){
double tmp=A.ang-B.ang;
if ( dcmp( tmp ) <0)
return 1;
if ( dcmp( tmp ) >0)
return 0;
if (dcmp( tmp ) ==0)
return (A.x*A.x)+(A.y*A.y)<(B.x*B.x)+(B.y*B.y);
}
Point a[MAXN],org;
int n;
set<Line> S;
bool vis[MAXN];
int main(){
while ( scanf("%d",&n)!=EOF)
{
scanf("%lf%lf",&org.x,&org.y);
for (int i=1;i<=n;i++)
{
Point A,B;
scanf("%lf%lf%lf%lf",&A.x,&A.y,&B.x,&B.y);
A=A-org; B=B-org;
A.ang=atan2(A.y,A.x);
B.ang=atan2(B.y,B.x);
if (cross(A,B)<0)
swap(A,B);///按照逆时针顺序规定线段的起点和终点
A.st_ed=0; B.st_ed=1;
A.id=i; B.id=i;
a[i*2-1]=A;
a[i*2]=B;
seg[i]=Line(A,B-A);
seg[i].id=i;
}
sort(a+1,a+2*n+1,cmp);
now=Line(Point(0,0),Point(-1,0));
S.clear();
memset(vis,0,sizeof(vis));
for (int i=1;i<=n*2;i++)
{
if (a[i].st_ed==0)
{
int x=a[i].id;
if ( ( dcmp ( cross(seg[x].p,now.v)*cross(now.v,seg[x].p+seg[x].v) ) >0 )&&( dcmp ( cross(seg[x].p,now.v)*cross(seg[x].p,seg[x].p+seg[x].v) ) >0 ))
S.insert( seg[x] );
}
}///插入与射线(-1,0)相交的线段
for (int i=1;i<=n*2;i++)
{
now=Line( Point(0,0), a[i]);///按逆时针顺序调整扫描线的角度
if (a[i].st_ed)
S.erase( seg[ a[i].id ] );
else
S.insert( seg[ a[i].id] );
if (! S.empty() )
vis[ S.begin()->id ] =1; ///因为插入一个元素以后,如果该元素是set中当前最小的元素,则该元素会成为set的第一个元素,所以可以这样使用set
///在这题里面最小元素是与当前扫描线相交的最近的元素
}
int ans=0;
for (int i=1;i<=n;i++)
if (vis[i])
ans++;
printf("%d\n",ans);
}
return 0;
}
HDU 3867 计算几何扫描线
最新推荐文章于 2023-12-21 16:37:37 发布