POJ3304

题意:有n条直线,求是否存在一条直线使得所有线段在这条直线上的投影有至少一个公共点。

方法:假设有一条直线满足题意,则必有所有的线段在这条直线上的投影交于一点,则过这点做这条直线的垂线,则这条垂线必定与所有的线段相交

反之,则假如有一条直线与所有的线段有交点,则做这条直线的垂线,那么这条直线与它的垂线的交点是所有线段投影与这条垂线的公共交点。

注意:1.线段与直线相交,线段在直线的两侧

            2.如果两个点的距离小于10^-8则为一个点,少了超时;

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define eps 1e-8
struct Point{
    double x,y;
}point[1005];
struct Line{
    Point a,b;
}line[1005];
double cross(Point p0,Point p1,Point p2)
{
    return (p0.x-p1.x)*(p2.y-p1.y)-(p2.x-p1.x)*(p0.y-p1.y);
}
int delcmp(double x)
{
    if( fabs(x)<eps )
        return 0;
    return x>0?1:-1;
}
int intersect(Point p0,Point p1,Point p2,Point p3)
{
    int d1=delcmp( cross(p0,p2,p3) );
    int d2=delcmp( cross(p1,p2,p3) );
    int d3=delcmp( cross(p2,p0,p1) );
    int d4=delcmp( cross(p3,p0,p1) );
    double d=cross( p2,p0,p1 )*cross( p3,p0,p1 );  //线段在直线的两侧;
    if( d<=0 ) return 1;   
    //if( d1*d2<=0&&d3*d4<=0 )
    //    return 1;
    return 0;
}
int equle(Point p0,Point p1)  //少了超时
{
    double d=sqrt( (p0.x-p1.x)*(p0.x-p1.x)+(p0.y-p1.y)*(p0.y-p1.y) );
    if( d<eps )
        return 0;
    return 1;

}
int main()
{
    int T;
    scanf("%d",&T);
    while( T-- )
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            double x1,y1,x2,y2;
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            point[i].x=x1;point[i].y=y1;
            point[n+i].x=x2;point[n+i].y=y2;
            line[i].a.x=x1;line[i].a.y=y1;
            line[i].b.x=x2;line[i].b.y=y2;
        }
        int flag=0;
        for(int i=1;i<=2*n&&!flag;i++)
        {
            for(int j=i+1;j<=2*n&&!flag;j++)
            {
                int sum=0;
                if( equle( point[i],point[j] ) ){  //不能少这个判断条件
                   for(int k=1;k<=n;k++)
                   {
                      if( intersect( point[i],point[j],line[k].a,line[k].b ) )
                      {
                         sum++;
                      }
                   }
                }
                if( sum==n )
                    flag=1;
            }
        }
        if( flag )
            printf("Yes!\n");
        else
            printf("No!\n");
    }
    return 0;
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值