2015年ALPC暑期专题练习I (计算几何) C

WR了N次,总结如下:

本题等价于找到一条和所有线段都相交的直线,再等价于枚举所有顶点中的两个顶点组成的线段,如果这个线段与所有线段相交,即为所求。

其中,只需要判断k循环中的线段两点c、d位于ab两侧即可,不需要判断ab位于cd两侧,JudgeLineCross没有用。

对于枚举的两个顶点,需要判断是否是同一个点(ZERO),并标记sign=0。因为假如最后一个点相同,那么j循环后sign=1,而实际上,并不能找到那条直线。

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<string>
#include<map>
#include<set>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
/**********************************************************/
const int MAX_NUM = 100+10;
const double ZERO = 0.00000001;
struct point{
  double x,y;
  point (double i,double j){x=i;y=j;}//普通构造函数
  point (const point& p){x=p.x;y=p.y;}//拷贝构造函数
  point& operator = (const point& p){//重载=
	x=p.x;y=p.y;
	return *this;
  }
  point (){}
};
struct segment : point {
  point a,b;
  segment (point x,point y){a=x;b=y;}
  segment (){}
  point getVector (){
	return point (b.x-a.x,b.y-a.y);
  }
};
double min_2 (double& a,double& b){return a<b?a:b;}
double max_2 (double& a,double& b){return a>b?a:b;}
double CrossMuti (point a,point b){return a.x*b.y-a.y*b.x;}
bool isZero (double x){return (x>=0&&x<ZERO)||(x<=0&&x>-1*ZERO); }
segment lineSet[MAX_NUM];
point pointSet[MAX_NUM*2];

bool JUdegPointInSegment (point& c,segment& ab)
{
  point ca = point (ab.a.x-c.x,ab.a.y-c.y);
  point cb = point (ab.b.x-c.x,ab.b.y-c.y);
  double xxx=ca.x*cb.x+ca.y*cb.y;
  if ( isZero(CrossMuti(ca,cb)) && (xxx<=-1*ZERO || isZero(xxx)) )
	return true;
}

bool JudgeLineCross (segment& ab,segment& cd)//判断两个线段是否相交
{
  if (JUdegPointInSegment (ab.a,cd) || JUdegPointInSegment (ab.b,cd) ||//有点在线段上
	  JUdegPointInSegment (cd.a,ab) || JUdegPointInSegment (cd.b,ab)
	  )
	return true;
  if ( min_2 (ab.a.x,ab.b.x)>max_2 (cd.a.x,cd.b.x) ||//快速排斥实验
	   min_2 (ab.a.y,ab.b.y)>max_2 (cd.a.y,cd.b.y) ||
	   min_2 (cd.a.x,cd.b.x)>max_2 (ab.a.x,ab.b.x) ||
	   min_2 (cd.a.y,cd.b.y)>max_2 (ab.a.y,ab.b.y)
	   )
	return false;
  point abVec = ab.getVector ();
  point cdVec = cd.getVector ();
  double sign1 = CrossMuti( point(cd.a.x-ab.a.x,cd.a.y-ab.a.y),abVec)*CrossMuti(point(cd.b.x-ab.a.x,cd.b.y-ab.a.y),abVec);
  double sign2 = CrossMuti( point(ab.a.x-cd.a.x,ab.a.y-cd.a.y),cdVec)*CrossMuti(point(ab.b.x-cd.a.x,ab.b.y-cd.a.y),cdVec);
  if (sign1<-1*ZERO && sign2 <-1*ZERO)//相交
	return true;
  else if (isZero (sign1) && isZero (sign2))//共线
	return true;
  else return false; 
}
bool isOnePoint (point& a,point& b)
{
  double len = sqrt (pow (a.x-b.x,2)+pow (a.y-b.y,2));
  return isZero (len);
}
/**********************************************************/
int main()
{
  int t,n;
  scanf ("%d",&t);
  while (t--)
  {
	scanf ("%d",&n);
	point a,b;
	for (int i=0; i < n; i++){
	  scanf ("%lf %lf %lf %lf",&a.x,&a.y,&b.x,&b.y);
	  lineSet[i].a=a;
	  lineSet[i].b=b;
	  pointSet[2*i]=a;
	  pointSet[2*i+1]=b;
	}
	int success=0,sign;
	if (n==1||n==2){
	  printf ("Yes!\n");
	  continue;
	}
	int i,j,k;
	for (i=0; i<2*n; i++){
	  for (j=i+1;j<2*n;j++){
		sign=1;
		if (isOnePoint (pointSet[i],pointSet[j])){
		  sign=0;
		  continue;
		}
		//segment l (pointSet[i],pointSet[j]);
		point ab (pointSet[j].x-pointSet[i].x,pointSet[j].y-pointSet[i].y);
		for (k=0;k<2*n;k+=2){
		  point ac (pointSet[k].x-pointSet[i].x,pointSet[k].y-pointSet[i].y);
		  point ad (pointSet[k+1].x-pointSet[i].x,pointSet[k+1].y-pointSet[i].y);
		  //if ( !JudgeLineCross (lineSet[k],l) ){
		  if ( CrossMuti (ac,ab)*CrossMuti (ad,ab)>=ZERO ){
			sign=0;
			break;
		  }
		}
		if (sign==1) break;
	  }
	  if (sign){
		success=1;
		//printf ("%d %d %d\n",i,j,k);
		break;
	  }
	}
	if (success)
	  printf ("Yes!\n");
	else printf ("No!\n");
  }
  return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值