版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/PK__PK/article/details/83110495
题目链接:http://poj.org/problem?id=3304
题意:给你n条线段,然后问是否存在一条直线,让所有线段在这条直线上的投影至少有一个公共点。
题解:我读题读了10年才读懂QAQ (太菜了)。这道题实际问的是是否存在一条直线与所有线段有交点。
如何从题意,转化到这里呢?
首先投影一定是和直线是垂直的,若所有直线至少有一个公共点,那么过这个公共点作垂线,一定和所有线段有交点。(读不懂画个图,显然的东西)。
然后问题就变成是否存在一条直线与所有线段有交点。再考虑,如何判断这条直线存不存在。
有如下几种情况。
1,没有交点。
2,有一个交点
3,有n个交点
若只存在一个交点,那么就是说这个交点是由线段的端点映射上的。所以我们只需要枚举任意两条线段的端点构成的直线,即是所求直线。然后问题有变成了判断线段相交。
判断线段相交,要理由快速排斥实验和跨立实验。其本质是利用叉积来判断。
以一条线段为标准,来判断另一条线段的端点是否在同一侧。
向量P×向量Q > 0 ,向量P在Q的顺时针方向
向量P×向量Q < 0 向量P 在Q的顺时针方向
向量P×向量Q == 0 在同一侧。
然后这道题 还需要判断重复的点 。切记。
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
const double eps = 1e-8;
const int N = 1005,maxn = 100005,inf = 0x3f3f3f3f3f;
struct point{
double x,y;
};
struct line{
point a,b;
}l[N];
int n;
double mul(point p,point u,point v){
return (u.x - v.x)*(p.y - u.y) - (u.y - v.y)*(p.x - u.x);
}
bool ok(point u,point v){
if(fabs(u.x - v.x) < eps && fabs(u.y - v.y) < eps) return 0; // 判重
for(int i = 0 ; i < n ; i ++)
if(mul(l[i].a,u,v) * mul(l[i].b,u,v) >= eps) return 0; // 叉积
return 1;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i = 0 ; i < n ; i ++)
scanf("%lf%lf%lf%lf",&l[i].a.x,&l[i].a.y,&l[i].b.x,&l[i].b.y);
bool flag = 0;
for(int i = 0 ; i < n && !flag ; i ++){ // 枚举 端点
for(int j = i+1 ; j < n && !flag ; j ++ )
if(ok(l[i].a,l[j].a) ||
ok(l[i].a,l[j].b) ||
ok(l[i].b,l[j].a) ||
ok(l[i].b,l[j].b)
)
flag = 1;
}
if(flag) printf("Yes!\n");
else printf("No!\n");
}
}