您的位置:首页 > 其它

POJ - 3304 Segments(计算几何)

2017-08-16 15:33 417 查看
点我看题

题意:给出一系列的线段,问是否存在一条直线,使得所有的线段在这条直线上的投影会交于一点。

分析:看完这个题,第一反应就想能不能转化为直线与线段的交,然后想去理清这个问题,画个图看看。



其中a为我们要找的直线,但是我们发现要判断是否存在一条a这样的直线是一件很困难的事情,因为我们没办法利用题目给的条件(n条线段的坐标),那么观察这个图,我们可以知道如果a存在,那么就一定存在与a垂直的一条直线b且b与其他n条线段有一个交点,那么整个题就转化为了问咱是否存在一条与其他n条线段都相交的线段。

那么我们可以一一枚举线段上这些点的两个端点形成一条直线,如果满足上述条件,则一定存在。

那么如何判断一条直线去某一线段是否相交呢那就要利用点的叉乘了,也就是线段Q1Q2的两个端点一定要在直线P1P2的左右两边,如下图



那么一定要满足(P1-Q1)×(p2-Q1)*(P1-Q2)×(P2-Q2) <= 0 才能表示直线与线段相交。

参考代码:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>

using namespace std;
#define eps 1e-8
const int maxn = 1e2+5;
int n;
struct Point{
double x,y;
Point(){}
Point( double xx, double yy)
{
x = xx;
y =yy;
}
Point operator - ( const Point &p)const
{
return Point(x-p.x,y-p.y);
}
//点的叉乘
double operator ^ ( const Point &p)const
{
return x*p.y-y*p.x;
}
//点的乘法(通常用于求两点距离)
double operator * ( const Point p)const
{
return x*p.x+y*p.y;
}
};
struct Line{
Point a,b;
Line(){}
Line( Point aa, Point bb)
{
a = aa;
b = bb;
}
};
Line line[maxn];

//计算叉乘(p2-p1)*(p3-p1)
double xmult( Point p1, Point p2, Point p3)
{
return (p2-p1)^(p3-p1);
}

//判断两点之间的距离
double dist( Point p1, Point p2)
{
return sqrt((p2-p1)*(p2-p1));
}

int sgn( double x)
{
if( fabs(x) < eps)
return 0;
if( x < 0)
return -1;
return 1;
}

//判断直线和线段是否相交 l1为直线,l2为线段
bool SegInterLine( Line l1, Line l2)
{
// if( xmult(l1.a,l2.a,l1.b)*xmult(l1.a,l1.b,l2.b) < 0)//这也是可以的,kuangbin的写法
// return false;
// return true;
if( xmult(l2.a,l1.a,l1.b)*xmult(l2.b,l1.a,l1.b) <= 0)
return true;
return false;
}

//判断p1p2是否与其他的线段相交
bool check( Line l)
{
if( sgn(dist(l.a,l.b)) == 0)//两个点重合
return false;
for( int i = 0; i < n; i++)
{
//判断直线和线段是否相交
// if( xmult(p1,line[i].a,p2)*xmult(p1,p2,line[i].b) < 0)
// return false;
if( !SegInterLine(l,line[i]))
return false;
}
return true;
}

int main()
{
int T;
scanf("%d",&T);
while( T--)
{
scanf("%d",&n);
double xa,ya,xb,yb;
for( int i = 0; i < n; i++)
{
scanf("%lf%lf%lf%lf",&xa,&ya,&xb,&yb);
line[i] = Line(Point(xa,ya),Point(xb,yb));
}

bool flag = false;
for( int i = 0; i < n; i++)
{
for( int j = 0; j < n; j++)
{
if( check(Line(line[i].a,line[j].a)) || check(Line(line[i].a,line[j].b)) || check(Line(line[i].b,line[j].a)) || check(Line(line[i].b,line[j].b)))
{
flag = true;
break;
}
}
}
if( flag)
puts("Yes!");
else
puts("No!");
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: