Codeforces 32E Hide and Seek [计算几何 对称点、线段相交]

题目大意:给出两个点,一个双面镜(线段),一面墙(线段),问两个点能否互相直接或间接地看到对方。

思路:两个点要么直接看到对方,这个直接判断一下两点连线是否和墙或者镜子相交就可以了。

            两个点通过镜子看到对方,首先两个点必须在镜子同侧,其次,其中一个点的对称点与另一个点的连线必须和镜子有交点,再次,光路上面不能出现墙(就是两条线段和墙判断是否有交)。

            求对称点的方法:先求出点A与对称轴L的交点(用向量叉积求面积比的方法)C,然后直接将点A到交点C的向量V累加到C上即可得到对称点。

            判断两条线段是否有交点的方法:先求出两条线段所在直线的交点C,然后判断C是不是同时落在两条线段上。

            判断一个点是否在线段上的方法:将其x和y分别与线段的左右端点的x、y比较即可。

            注意一个坑:光路和墙共线的时候也会被挡住。

#include 
#include 
#include 
#define db double
#define eps 1e-8
#define rep(i,j,k) for (i=j;i<=k;i++)
using namespace std;
struct pt{
	db x,y;
	pt (db X=0,db Y=0) {x=X; y=Y;}
	pt operator + (const pt &B)  { return pt(x+B.x,y+B.y); }
	pt operator - (const pt &B)  { return pt(x-B.x,y-B.y); }
	db operator * (const pt &B)  { return x*B.y-B.x*y;	   }
	pt operator * (const db &c) { return pt(x*c,y*c);	   }
}A,B,C,D;
struct seg{
	pt s,e,v;
	seg () {}
	seg (pt S,pt E) {s=S; e=E; v=E-S;}
}mir,wal;
pt crs(seg A,seg B)
{
	db S1=(B.s-A.s)*A.v,S2=A.v*B.v;
	return B.s+(B.v*(S1/S2));
}
bool onit(pt C,seg A)
{
	if ((C.xmax(A.s.x,A.e.x)+eps)) return 0;
	if ((C.ymax(A.s.y,A.e.y)+eps)) return 0;
	return 1;	
}
bool cross(seg A,seg B,int md)
{
	if (fabs(A.v*B.v)eps) return 1;
	return 0;
}
bool case_2()
{
	int ca=sgn((A-mir.s)*mir.v),cb=sgn((B-mir.s)*mir.v);
	if (!((ca<0 && cb<0) || (ca>0 && cb>0))) return 0;
	if (!cross(seg(A,D),mir,0)) return 0;	
	C=crs(seg(A,D),mir);
	if (cross(seg(A,C),wal,1)) return 0;
	if (cross(seg(C,B),wal,1)) return 0;
	return 1;
}
int main()
{
//	freopen("mirror.in","r",stdin);
//	freopen("mirror.out","w",stdout);
	scanf("%lf%lf%lf%lf",&A.x,&A.y,&B.x,&B.y);
	scanf("%lf%lf%lf%lf",&wal.s.x,&wal.s.y,&wal.e.x,&wal.e.y); wal.v=wal.e-wal.s;
	scanf("%lf%lf%lf%lf",&mir.s.x,&mir.s.y,&mir.e.x,&mir.e.y); mir.v=mir.e-mir.s;
	C=B+pt(-mir.v.y,mir.v.x); C=crs(seg(B,C),mir); D=C+(C-B);
	if (case_1() || case_2()) printf("YES\n");
	else printf("NO\n");
	return 0;
}

你可能感兴趣的:(计算几何)