POJ3304 Segments 计算几何 叉积

题目链接
题意:
给你若干条线段,求他们是否能投影到一条直线上,使得每条线段的投影至少有一个公共交点。

题解:
我们过那个公共交点作那条直线的垂线,根据投影的性质,不难发现这条直线应该与所有线段有交点。那么就转化为了判断是否有一条直线与所有的线段都有交点就行了。那么现在的问题是该如何找直线呢。稍微思考一下,我们会发现好像每条线段只有两个端点是有用的,对于所有合法的直线,最边界的合法情况就是经过了某条线段的一个端点,于是我们枚举线段端点,用两个线段端点连形组成的直线来判断是否与每条线段都有交即可。判断的方法是用叉积,利用叉积的结果是根据两向量的位置关系有正有负的。选择两个端点中的一个作为向量的起点,另一个端点作为终点,同时其他所有线段的两个端点分别作为终点作叉积,如果对于两个端点的叉积一正一反,则说明该线段的两个端点分别在当前直线两侧,也就是有交点,当然叉积为0重合也是有交点。这题就这样做完了。
代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cmath>
using namespace std;

int t,n,pd;
double eps=1e-8;
struct Point
{
    double x,y;
};
int cmp(double x)
{
    if(fabs(x)<eps)
    return 0;
    if(x>0)
    return 1;
    else
    return -1;
}
bool operator != (Point x,Point y)
{
    return (cmp(x.x-y.x)!=0||cmp(x.y-y.y)!=0);
}
struct Vector
{
    double x,y;
};
struct Line
{
    Point p,q;
}l[110];
double chaji(Vector x,Vector y)
{
    return x.x*y.y-x.y*y.x;
}
int check(Point x,Point y)
{
    Vector v1;
    v1.x=x.x-y.x;
    v1.y=x.y-y.y;
    for(int i=1;i<=n;++i)
    {
        Point b=l[i].p,c=l[i].q;
        Vector v2,v3;
        v2.x=b.x-y.x;
        v2.y=b.y-y.y;
        v3.x=c.x-y.x;
        v3.y=c.y-y.y;
        int ji1,ji2;
        ji1=cmp(chaji(v1,v2));
        ji2=cmp(chaji(v1,v3));
        if(ji1!=ji2||!ji1)
        continue;
        else
        return 0;
    }
    return 1;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        pd=0;
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
        scanf("%lf%lf%lf%lf",&l[i].p.x,&l[i].p.y,&l[i].q.x,&l[i].q.y);
        for(int i=1;i<=n;++i)
        {
            for(int j=i;j<=n;++j)
            {
                Point x,y;
                x=l[i].p;
                y=l[j].p;
                if(x!=y)
                {
                    if(check(x,y))
                    {
                        pd=1;
                        break;
                    }
                }
                x=l[i].p;
                y=l[j].q;
                if(x!=y)
                {
                    if(check(x,y))
                    {
                        pd=1;
                        break;
                    }
                }
                x=l[i].q;
                y=l[j].p;
                if(x!=y)
                {
                    if(check(x,y))
                    {
                        pd=1;
                        break;
                    }
                }
                x=l[i].q;
                y=l[j].q;
                if(x!=y)
                {
                    if(check(x,y))
                    {
                        pd=1;
                        break;
                    }
                }
            }
        }
        if(pd==1)
        printf("Yes!\n");
        else
        printf("No!\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_shi/article/details/81807872