poj 3304——Segments

大致题意:给n条线段,判断是否存在一条线段,使得所有的线段在它上面的投影是否有公共交点。

大致思路:既然是投影,那很明显在纸上画一下就知道,以某条线段作为x轴建立直角坐标系,那就可以轻松的

画出每条线段在x轴上的投影,也就很容易就知道,判断投影有没有公共点,其实就是看有没有一条直线可以穿过所有的线段。

这里其实稍微跳了一点,但是画图就很容易知道我在说什么。看题目的数据范围n为100,所以暴力枚举任意两个的端点,判断这两个端点的直线是否可以穿过所有的线段。注:枚举的时候,如果两个端点的距离小于1e-8,就认为是同一个点,这次枚举的端点不算。

同时,通过上面的分析,大胆猜测口嗨一下,如果不考虑线段旋转的精度误差,应该可以枚举旋转线段,暴力判断所有线段的左端点的x坐标都小于min(所有线段的右端点的x坐标)。瞎吹一会,不要在意。

最后,代码:

#include<iostream>
#include<stdio.h>
#include<math.h>
using namespace std;
int n;
struct line
{
    double x1,y1,x2,y2;
}lines[120];
double multiple_cross(double x1,double y1,double x2,double y2)
{
    return x1*y2-x2*y1;
}
bool check(line a,line b)
{
    double w,z;
    w=multiple_cross(a.x1-b.x1,a.y1-b.y1,b.x2-b.x1,b.y2-b.y1);
    z=multiple_cross(a.x2-b.x1,a.y2-b.y1,b.x2-b.x1,b.y2-b.y1);
    if(w*z<=0)
        return true;
    return false;
}
bool judge(line ac)
{
    if(sqrt((ac.x1-ac.x2)*(ac.x1-ac.x2)+(ac.y1-ac.y2)*(ac.y1-ac.y2))<1e-8)
        return false;
    bool flag=true;
    for(int i=0;i<n;++i)
    {
        if(!check(lines[i],ac))
            flag=false;
    }
    return flag;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=0;i<n;++i)
        {
            scanf("%lf %lf %lf %lf",&lines[i].x1,&lines[i].y1,&lines[i].x2,&lines[i].y2);
        }
        if(n==1||n==2)
        {
            printf("Yes!\n");
            continue;
        }
        line ac;
        bool flag=false;
        for(int i=0;i<n;++i)
        {
            for(int j=i+1;j<n;++j)
            {
                ac.x1=lines[i].x1,ac.y1=lines[i].y1;
                ac.x2=lines[j].x1,ac.y2=lines[j].y1;
                if(judge(ac))
                {
                    flag=true;
                }
                ac.x2=lines[j].x2,ac.y2=lines[j].y2;
                if(judge(ac))
                {
                    flag=true;
                }
                ac.x1=lines[i].x2,ac.y1=lines[i].y2;
                if(judge(ac))
                {
                     flag=true;
                }
                ac.x2=lines[j].x1,ac.y2=lines[j].y1;
                if(judge(ac))
                {
                    flag=true;
                }
            }
        }
        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、付费专栏及课程。

余额充值