poj 3304 判断线段与直线交

本文探讨如何确定是否存在一条直线能通过所有给定线段的投影,进而找到穿过所有线段的直线,并通过叉积判断线段与直线的相交情况。

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

这道题是求是否存在一条直线导致所有给定线段在这条直线上的投影是否有共同的交点,那么从这点做该条直线的垂线,一定能够交到所有的线段(根据投影的性质得到),所以问题转化成了能否找到一条直线穿过所有的线段,我们能够通过叉积判断一条线段和直线是否相交,那么我们可以枚举每两个端点组成的直线,因为凡是满足穿过所有线段的直线,一定可以通过旋转得到一个正好和至少有两个端点在直线上的临界状态.

注意判断端点距离极小时的情况,得到的叉积可能为0影响判断


#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define eps 1e-8
#define MAX 207

using namespace std;

struct Point 
{
    double x,y;
    Point ( ) : x(0) , y(0){}
    Point ( double a , double b ) : x(a),y(b){}
};

struct Line 
{
    Point start,end;
};

double cross ( Point p , Point p1 , Point p2 )
{
    return ( p.x - p2.x )*( p1.y - p2.y )-( p1.x - p2.x )*( p.y - p2.y); 
}

bool intersect ( Line l , Point a , Point b )
{
    if ( cross( l.start,a,b) * cross ( l.end,a,b) <= 0 )
       return  true;
    else return false;
}

bool equal ( Point a , Point b )
{
    if ( fabs(a.x-b.x)<eps && fabs(a.y-b.y)<eps ) return true;
    else return false;
}

Point p[MAX];
Line  l[MAX];
int n;

bool judge ( )
{
    for ( int i = 1 ; i <= 2*n ; i++ )
        for ( int j = 1 ; j <= 2*n ; j++ )
        {
            if ( equal(p[i],p[j])) continue;
            int k;
            for ( k = 1 ; k <= n ; k++ )
            {
                if ( !intersect ( l[k] , p[i] , p[j]))
                    break;
            }
            if ( k==n+1 ) return true;
        }
    return false;
}

int main ( )
{
    int t;
    scanf ( "%d" , &t );
    while ( t-- )
    {
        scanf ( "%d" , &n );
        for ( int i=1,j=1; j<=n; i++,j++ )
        {
            scanf ( "%lf%lf" , &p[i].x , &p[i].y );
            l[j].start.x = p[i].x;
            l[j].start.y = p[i].y;
            i++;
            scanf ( "%lf%lf" , &p[i].x , &p[i].y );
            l[j].end.x = p[i].x;
            l[j].end.y = p[i].y;
        }
        if ( judge ( ) ) puts ( "Yes!" );
        else puts ( "No!" );
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值