POJ 3304 Segments
思路:构造一条直线能经过所有的线段,这些交点的投影将会是一个公共的点。
然后就是利用叉乘判断直线与线段是否有交点,以及一个非常重要的思路就是枚举所有线段的任意两个端点来构造这条直线。
如果存在这样子一条直线,那么这条直线在所有线段中平移、旋转(在与所有线段相交的情况下),可以碰到线段中的两个端点。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
double eps = 1e-8;
struct Point
{
double x,y;
Point(double xx= 0, double yy = 0):x(xx), y(yy){}
}p[100000];
typedef Point Vector;
struct Line
{
Point a, b;
Line(){}
Line(Point aa, Point bb):a(aa),b(bb){}
}line[100000];
int sgn(double x){
if(fabs(x) < eps)
return 0;
if(x < 0)
return -1;
return 1;
}
bool operator == (const Point& a, const Point& b){
if(sgn(a.x-b.x) == 0 && sgn(a.y-b.y) == 0)
return true;
return false;
}
Vector operator-(Point A, Point B)
{
return Vector(A.x-B.x, A.y-B.y);
}
double Cross(Vector A, Vector B)
{
return A.x*B.y - A.y*B.x;
}
bool LineIntersection(Point a, Point b, Point c, Point d)
{
return Cross( b-a,c-a)*Cross( b-a,d-a) <=0;
}
bool check(Point a, Point b, int n)
{
for(int i = 0;i<n;i++)
{
if(!LineIntersection(a, b, line[i].a,line[i].b))
return false;
}
return true;
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int n,cnt = 0;
double x1,x2,y1,y2;
scanf("%d", &n);
for(int i = 0;i<n;i++)
{
scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
line[i] = Line(Point(x1,y1),Point(x2,y2));
p[cnt++]= Point(x1,y1);
p[cnt++] =Point(x2,y2);
}
bool flag = false;
for(int i = 0;i<cnt;i++)
{
flag = false;
for(int j = i+1;j<cnt;j++)
{
if(p[i] == p[j])
continue;
if(check(p[i],p[j],n))
flag = true;
if(flag)break;
}
if(flag) break;
}
if(flag) printf("Yes!\n");
else
printf("No!\n");
}
return 0;
}
图片来源:[(17条消息) POJ - 3304 – Segments【直线与线段相交 】_星空皓月的博客-CSDN博客_直线与线段相交]