poj 3304 Segments 线段与直线的关系

本文探讨了给定多个二维空间线段的情况下,寻找是否存在一条直线,使得所有线段在此直线上的投影至少有一个公共交点的问题。通过转换为寻找与所有线段相交的直线的方法,提出了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Segments
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 12809 Accepted: 4076

Description

Given n segments in the two dimensional space, write a program, which determines if there exists a line such that after projecting these segments on it, all projected segments have at least one point in common.

Input

Input begins with a number T showing the number of test cases and then, T test cases follow. Each test case begins with a line containing a positive integer n ≤ 100 showing the number of segments. After that, n lines containing four real numbers x1 y1 x2 y2 follow, in which (x1y1) and (x2y2) are the coordinates of the two endpoints for one of the segments.

Output

For each test case, your program must output "Yes!", if a line with desired property exists and must output "No!" otherwise. You must assume that two floating point numbers a and b are equal if |a - b| < 10-8.

Sample Input

3
2
1.0 2.0 3.0 4.0
4.0 5.0 6.0 7.0
3
0.0 0.0 0.0 1.0
0.0 1.0 0.0 2.0
1.0 1.0 2.0 1.0
3
0.0 0.0 0.0 1.0
0.0 2.0 0.0 3.0
1.0 1.0 2.0 1.0

Sample Output

Yes!
Yes!
No!

Source



题意:给出n条线段(n<=100),问是否存在一条直线,使得所有线段在这条直线上的投影有至少一个公共交点。


解:1.问题等价于找到是否存在一条直线line2与所有线段相交,这条直线与所求直线line就是垂直关系。

2.这点真的没想到。感觉肯定跟端点有关,却偏偏没想出来。解法就是枚举两条线段的端点,构成一条直线,判断是否存在这样一条直线与所有线段相交。


#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;

#define all(x) (x).begin(), (x).end()
#define for0(a, n) for (int (a) = 0; (a) < (n); (a)++)
#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)
#define mes(a,x,s)  memset(a,x,(s)*sizeof a[0])
#define mem(a,x)  memset(a,x,sizeof a)
#define ysk(x)  (1<<(x))
typedef long long ll;
typedef pair<int, int> pii;
const int INF =0x3f3f3f3f;
const int maxn=  100  ;
int n;
struct Point
{
    double x,y;
    Point(double x=0,double y=0):x(x),y(y) {};
};
typedef Point Vector;
Vector operator +(Vector A,Vector B) {return Vector(A.x+B.x,A.y+B.y); }
Vector operator -(Vector A,Vector B) {return Vector(A.x-B.x,A.y-B.y); }
Vector operator *(Vector A,double p) {return Vector(A.x*p,A.y*p); }
Vector operator /(Vector A,double p) {return Vector(A.x/p,A.y/p); }
Vector operator -(Vector A)  {return  Vector(-A.x,-A.y);}

const double eps=1e-8;
int dcmp(double x)
{
    if(fabs(x)<eps)  return 0;
    else return x<0?-1:1;
}
bool operator ==(Point A,Point B) {return dcmp(A.x-B.x)==0&&dcmp(A.y-B.y)==0;}

double Cross(Vector A,Vector B)//叉乘
{
    return A.x*B.y-A.y*B.x;
}

struct Line
{
    Point p,p2;
    Vector v;
    Line(){}
    Line(Point p,Vector v):p(p),v(v){}//点线式
    void twoPointIntial(Point p,Point p2)//两点式
    {
        this->p=p;
        this->p2=p2;
        v=  p2-p;
    }

}seg[maxn+5];

typedef Line Seg;


bool intersect(Line a,Seg b)//判断直线和线段是否相交
{
    Point A=b.p;
    Point B=b.p2;
    Vector v1=a.p-A;
    Vector v2=a.p2-A;
    Vector v3=a.p-B;
    Vector v4=a.p2-B;
    return  dcmp(Cross(v1,v2))*dcmp(Cross(v3,v4))<=0; //如果线段的端点在直线上,肯定相交
}
bool solve(Point A,Point B)
{
     Line L;L.twoPointIntial(A,B);
     if( A==B )  return false;
     for(int i=0;i<n;i++)
     {
         if(!intersect(L,seg[i])    )   return false;
     }
     return true;

}
int main()
{
   std::ios::sync_with_stdio(false);
   int T;cin>>T;
   while(T--)
   {
      cin>>n;
      for0(i,n)
      {
          cin>>seg[i].p.x>>seg[i].p.y>>seg[i].p2.x>>seg[i].p2.y;
      }
      if(n==1)  {puts("Yes!");continue;}
      bool find=false;
      for(int i=0;i<n&&!find;i++)
      {
          for(int j=i+1;j<n;j++)
          {
              find|=  solve(seg[i].p ,seg[j].p);
              find|=  solve(seg[i].p ,seg[j].p2);
              find|=  solve(seg[i].p2 ,seg[j].p);
              find|=  solve(seg[i].p2 ,seg[j].p2);
              if(find)  break;
          }
      }

      puts(find?"Yes!":"No!");
   }
   return 0;
}



评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值