您的位置:首页 > 其它

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

2015-07-19 13:21 281 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  计算几何