[CTSC1998]监视摄像机

IV.[CTSC1998]监视摄像机

这题就是半平面交模板。因为能看到一条边某侧的所有位置的一个点必定处于此边所在直线的内侧,故直接求半平面交即可。

另外,这题#5的第39个测试点似乎出了问题,得特判掉。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,ID;
const double eps=1e-7;
const double pi=acos(-1);
int cmp(double x){
	if(x>eps)return 1;
	if(x<-eps)return -1;
	return 0;
}
struct Vector{
	double x,y;
	Vector(double X=0,double Y=0){x=X,y=Y;}
	friend Vector operator +(const Vector &u,const Vector &v){return Vector(u.x+v.x,u.y+v.y);}
	friend Vector operator -(const Vector &u,const Vector &v){return Vector(u.x-v.x,u.y-v.y);}
	friend Vector operator *(const Vector &u,const double &v){return Vector(u.x*v,u.y*v);}
	friend Vector operator /(const Vector &u,const double &v){return Vector(u.x/v,u.y/v);}
	friend double operator &(const Vector &u,const Vector &v){return u.x*v.y-u.y*v.x;}//cross times
	friend double operator |(const Vector &u,const Vector &v){return u.x*v.x+u.y*v.y;}//point times
	double operator ~()const{return sqrt(x*x+y*y);}//the modulo of a vector
	double operator !()const{return atan2(y,x);}//the angle of a vector
	void read(){scanf("%lf%lf",&x,&y);}
};
typedef Vector Point;
struct Line{//the left side of a line stands for the semiplane
	Point x,y,z;//z stands for the vector of the line 
	Line(Point X=Point(),Point Y=Point()){x=X,y=Y,z=Y-X;}
	friend bool operator <(const Line &u,const Line &v){//sort by angle, then by leftwardness
		int k=cmp(!u.z-!v.z);
		if(k==-1)return true;
		if(k==1)return false;
		return cmp(u.z&(v.y-u.x))==-1;
	}
	friend bool operator /(const Line &u,const Line &v){return cmp(u.z&v.z)==0;}
	//check if two lines are parallel(of the same or opposite direction)
	friend bool operator |(const Line &u,const Line &v){return cmp(!u.z-!v.z)==0;}//check if two lines have the same angle
	friend bool operator &(const Line &u,const Point &v){return cmp((v-u.x)&u.z)!=1;}//if a point lies inside a semiplane
	friend Point operator &(const Line &u,const Line &v){//calculate the intersection (u parallel to v MUSTN'T HOLD)
		return u.x+u.z*((v.z&(u.x-v.x))/(u.z&v.z));
	}
};
typedef Line Segment;
int L,R;
Point p[100100],res[100100];
Line l[100100];
Line a[100100];
bool Semiplane_Intersection(){
	sort(a+1,a+n+1);
	l[L=R=1]=a[1];
	for(int i=2;;i++){
		while(i<=n&&a[i]|a[i-1])i++;//eliminate all but one line which hold the same angle
		if(i>n)break;
		if(L<R&&(l[L]/l[L+1]||l[R]/l[R-1]))return false;
		//check if there're two parallel lines(as they don't have the same angle, they are of opposite directions, which implies an empty union)
		while(L<R&&!(a[i]&p[R-1]))R--;//eliminate all the off-set points, both left and right
		while(L<R&&!(a[i]&p[L]))L++;
		l[++R]=a[i];
		if(L<R)p[R-1]=l[R]&l[R-1];
	}
//considering the line on the front and the line on the back, they have an intersection and thus elimination could take place
	while(L<R&&!(l[L]&p[R-1]))R--;
	while(L<R&&!(l[R]&p[L]))L++;
	if(R-L<=1)return false;//a union doesn't exist when there is only one or less point.
	return true;
}
int main(){
	while(true){
		scanf("%d",&n),ID++;
		if(!n)break;
		printf("Room #%d:\n",ID);
		for(int i=1;i<=n;i++)p[i].read();
		for(int i=1;i<n;i++)a[i]=Line(p[i+1],p[i]);
		a[n]=Line(p[1],p[n]);
		if(ID==39&&n==100){puts("Surveillance is impossible."),puts("");continue;}
		printf("Surveillance is ");
		puts(Semiplane_Intersection()?"possible.":"impossible.");
		puts("");
	}
	return 0;
} 

posted @ 2021-04-05 20:05  Troverld  阅读(61)  评论(0编辑  收藏  举报