1016 - 计算几何之直线与线段的交 - Segments(POJ 3304)
程序员文章站
2022-04-01 15:51:10
...
题意
虽然题目是给了什么投影啊,什么奇奇怪怪的东西
但实际上也就是给你 n 条线段,询问是否存在一条直线能经过所有的线段
数据范围:n<=100
分析
这个数据范围有点友好啊……
我们先来想一个问题
若存在一条直线使其能穿过所有的线段,那我们一定可以将这条线段进行一定角度的旋转,然后使其恰好被卡在某两条线段的端点之间
也就是说若我们能够找到被某两个线段端点卡住的直线,使其穿过所有的线段,则一定存在一组合法解
根据逆反定理,若我们找不到这样的直线,则原题一定不存在合法解
由于数据范围很友好,我们就直接暴力枚举(n^3)
代码
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define eps 1e-8
#define N 105
using namespace std;
int T,n;
struct Point{
double x,y;
Point(){}
Point(double _x,double _y):x(_x),y(_y){}
friend inline Point operator +(const Point &a,const Point &b){
return Point(a.x+b.x,a.y+b.y);
}
friend inline Point operator -(const Point &a,const Point &b){
return Point(a.x-b.x,a.y-b.y);
}
friend inline Point operator *(double k,const Point &a){
return Point(k*a.x,k*a.y);
}
friend inline double dot(const Point &a,const Point &b){
return (a.x*b.x+a.y*b.y);
}
friend inline double cross(const Point &a,const Point &b){
return (a.x*b.y-b.x*a.y);
}
friend inline double len(const Point &a){
return sqrt(dot(a,a));
}
friend inline double dis (const Point &a,const Point &b){
return len(a-b);
}//向量常见的运算
};
struct Line{
Point a,b;
}line[N];
bool check(Point x,Point y){
if(dis(x,y)<eps) return false;//必须要要的
for(int i=1;i<=n;++i){
if(cross(x-line[i].a,y-line[i].a)*cross(x-line[i].b,y-line[i].b)>eps) return false;
}
return true;
}
int main(){
scanf("%d",&T);
int i,j,k;
while(T--){
scanf("%d",&n);
for(i=1;i<=n;++i)
scanf("%lf%lf%lf%lf",&line[i].a.x,&line[i].a.y,&line[i].b.x,&line[i].b.y);
if(n==1){ printf("Yes!\n");continue; }
int flag=0;
for(i=1;i<n;++i)
{
for(j=i+1;j<=n;++j){
if(check(line[i].a,line[j].a)||check(line[i].a,line[j].b)||check(line[i].b,line[j].a)||check(line[i].b,line[j].b)){
flag=1;
break;
}
}
if(flag){
printf("Yes!\n");
break;
}
}
if(!flag) printf("No!\n");
}
return 0;
}