poj 3304 Segments

 http://poj.org/problem?id=3304

题意:给你一些线段,让你判断是否存在一条直线,使这些线段在这条直线上面的投影至少相交于一点(有可能是线段)

解题思路:假设存在这样的一条直线,则过相交区域的一个点做这条直线的垂线必定和所有的线段都相交,然后将这条线段进行平移,直到与这些线段的一个最近的端点相交为

止,当然,如果相交区域是一个点,则垂线不需要平移就会和某条线段的一个端点相交,然后将这条平移后的直线沿着这个最先相交的端点进行旋转,直到和其他的任意一个端

点相交,这个时候,这条经过平移、旋转的直线可以看成是过这两个端点的直线,也必定和所有的线段都相交。

刚开始,我一直搞不明白在直线绕第一个相交的端点进行旋转直到和第二个端点相交的时候为什么会过所有的线段。经过小媛大牛的指点才明白了,如果经过旋转的直线不是和

所有的线段相交,那么必定存在平行于这条直线的线段,那么这条直线在旋转的时候第一个相交的端点就不会是现在的这个端点,而是与现在的直线平行的那条线段的一个端

点。非常感谢小媛大牛!

思路明白以后,代码是很容易用模板写出来的

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

using namespace std;

#define eps 1e-9

const int maxn=102;

//点
struct point
{
   double x,y;
}s[2*maxn];

//线段
struct Seg
{
   point a,b;
}seg[maxn];

//重载最大值、最小值计算函数
double min(double x,double y)
{return x<y?x:y;}
double max(double x,double y)
{return x>y?x:y;}

//判断double型的正数、负数和0,分别相应的返回1、-1和0
int dblcmp(double x)
{
   if(x==0) return 0;
   return (x>0)?1:-1;
}
//计算叉积
double det(double x1,double y1,double x2,double y2)
{return x1*y2-x2*y1;}

//计算a,b,c三点的叉积,判断a,b,c三点的位置关系
double cross(point a,point b,point c)
{return det(b.x-a.x,b.y-a.y,c.x-a.x,c.y-a.y);}

//计算两点间的最短距离
double dist(point a,point b)
{return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}

//判断线段是否相交,相交为true,不相交为false
bool segcross(point a,point b,point c,point d)
{
   int d1,d2,d3,d4;
   d1=dblcmp(cross(a,b,c));
   d2=dblcmp(cross(a,b,d));
   d3=dblcmp(cross(c,d,a));
   d4=dblcmp(cross(c,d,b));
   if((d1^d2)==-2&&(d3^d4)==-2) return true;
   return false;
}

//判断直线ab和线段cd是否相交,相交为true,不相交为false
bool linecross(point a,point b,point c,point d)
{
   int d1,d2;
   d1=dblcmp(cross(a,c,b));
   d2=dblcmp(cross(a,d,b));
   if(d1*d2>0) return false;
   return true;
}

bool fun(int t,int n)
{
   for(int i=0;i<t;i++)
   {
      for(int j=i+1;j<t;j++)
      {
         int k;
         if(!dblcmp(s[i].x-s[j].x)&&!dblcmp(s[i].y-s[j].y)) continue;
         for(k=0;k<n;k++)
         {
            if(!linecross(s[i],s[j],seg[k].a,seg[k].b))
               break;
         }
         if(k>=n) return true;
      }
   }
   return false;
}

int main()
{
   double x1,y1,x2,y2;
   int t,n;
   scanf("%d",&t);
   while(t--)
   {
      scanf("%d",&n);
      int t=0;
      for(int i=0;i<n;i++)
      {
         cin>>x1>>y1>>x2>>y2;
         s[t].x=x1,s[t++].y=y1;
         s[t].x=x2,s[t++].y=y2;
         seg[i].a.x=x1,seg[i].a.y=y1;
         seg[i].b.x=x2,seg[i].b.y=y2;
      }
      if(fun(t,n)) printf("Yes!\n");
      else printf("No!\n");   
   }
  
   return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值