POJ 3304 (判断直线和线段的交)

Segments
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 15777 Accepted: 5011
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 (x1, y1) and (x2, y2) 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

Amirkabir University of Technology Local Contest 2006

做法:假设存在这么一条直线,则过所有线段在这条直线上的投影的交集上任意一点做直线的垂线,那么这个垂线一定和所有直线相交,问题就转换成了是否存在一条直线与所有线段相交。且投影的两端肯定是由某线段或某两个线段的端点投影而来的,枚举端点,看形成的直线和所有线段是否有交即可。

**判断直线与线段相交的方法:
直线和线段有交点肯定是线段的两个端点不在直线的同侧
也就是说两个端点分别和直线的叉积,乘起来是<=0的,利用这个特性我们可以判断它们的关系**

注意:这道题会出现直线的两端在同一个点的情况,遇到这种情况肯定就是 No!了,我们就要判断一下两个端点的距离是不是小于eps,是的话就是重合了。
PS:求叉积double写成int,GG……..

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <stack>
#include <vector>
#define maxn 10010
#define maxe 100010
typedef long long ll;
using namespace std;
const double eps=1e-8;
const int inf=0x3f3f3f3f3f;
int sgn(double x)
{
    if(fabs(x) < eps)return 0;
    if(x < 0) return -1;
    return 1;
}
struct Point
{
    double x,y;
    Point(){};
    Point(double a,double b)
    {
        x=a,y=b;
    }
    void input()
    {
        scanf("%lf%lf",&x,&y);
    }
    Point operator +(Point a)
    {
        Point b(x+a.x,y+a.y);
        return b;
    }
    Point operator -(Point a)
    {
        Point b(x-a.x,y-a.y);
        return b;
    }
    double operator *(Point a)
    {
        return x*a.x+y*a.y;
    }
    double operator ^(Point a)
    {
        return x*a.y-y*a.x;
    }
    bool operator <(Point a)
    {
        return x<a.x;
    }
    double len()
    {
        return sqrt(x*x+y*y);
    }

};
double mul(Point p0,Point p1,Point p2)
{
    return (p1-p0)^(p2-p0);
}
double dis(Point a,Point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
struct Line
{
    Point a,b;
    double k,d;
    bool flag;
    void prepare()
    {
        if(a.x-b.x!=0)
        k=(a.y-b.y)*1.0/(a.x-b.x),flag=true,d=a.y-k*a.x;
        else flag=false,d=a.x;
    }
    Line(Point st,Point ed)
    {
        a=st;
        b=ed;
        prepare();

    }
    Line(){};
    void input()
    {
        a.input();
        b.input();
        prepare();
    }
    int operator *(Line l)
    {
        return (a-b)*(l.a-l.b);
    }
    int operator ^( Line l)
    {
        return (a-b)^(l.a-l.b);
    }
    Point intersect(Line l)
    {
        Point r;double x,y;
        if(!flag&&l.flag)
        {
            x=d;
            y=l.k*x+l.d;
        }
        else if(flag&&!l.flag)
        {
            x=l.d;
            y=k*x+d;
        }
        else
        {
            x=(l.d-d)/(k-l.k);
            y=k*x+d;
        }
        r.x=x;
        r.y=y;
        return r;

    }

}l[maxn];
//line l1,segment l2
bool check(Line l1,Line l2)
{
    return sgn(mul(l2.a,l1.a,l1.b))*sgn(mul(l2.b,l1.a,l1.b))<=0;
}
bool judge(Line l1,int n)
{
    if(sgn(dis(l1.a,l1.b))==0)return false;
    for(int i=0;i<n;i++)
    {
        if(check(l1,l[i])==false)
            return false;
    }
    return true;
}
int main()
{
    int t;
    int n;
    //freopen("in.txt","r",stdin);

    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            l[i].input();
        }
        bool flag=false;
        for(int i=0;i<n&&!flag;i++)
            for(int j=0;j<n&&!flag;j++)
                if(judge(Line(l[i].a,l[j].a),n) || judge(Line(l[i].a,l[j].b),n)
                        || judge(Line(l[i].b,l[j].a),n) || judge(Line(l[i].b,l[j].b),n) )
                {
                    flag=true;
                    break;
                }
        if(flag)
            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、付费专栏及课程。

余额充值