URAL 1111 Squares(求点到正方形的距离)

URAL 1111 Squares(求点到正方形的距离)

题意:

       给你一个点P和n个正方形(不一定平行坐标轴),要你求这个点P到每个正方形的最小距离且按距离从小到大输出正方形的编号. 如果点P在某个正方形内部,那么距离为0. 每个正方形仅给出一条对角线的两个顶点.

分析:

       首先根据正方形的一条对角线旋转90度,然后用中点加上(或减去)旋转后向量的一半可以得到正方形的另外两个点.

       然后判断该正方形是否包含了点P,如果没有包含,那么点P到正方形的距离就是P点到正方形4条线段的距离了.

       之后对所有正方形按距离从小到大(相同距离就按编号从小到大)做一次排序即可.

       模板用的刘汝佳<<训练指南>>上的.

AC代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const double eps=1e-14;
const double PI=acos(-1.0);
int dcmp(double x)
{
    if(fabs(x)<eps) return 0;
    return x<0?-1:1;
}
struct Point
{
    double x,y;
    Point(){}
    Point(double x,double y):x(x),y(y){}
};
typedef Point Vector;
bool operator==(Point A,Point B)
{
    return dcmp(A.x-B.x)==0&&dcmp(A.y-B.y)==0;
}
Vector operator-(Point A,Point B)
{
    return Vector(A.x-B.x,A.y-B.y);
}
Vector operator+(Vector A,Vector B)
{
    return Vector(A.x+B.x,A.y+B.y);
}
Vector operator*(Vector A,double p)
{
    return Vector(A.x*p,A.y*p);
}
double Dot(Vector A,Vector B)
{
    return A.x*B.x+A.y*B.y;
}
double Length(Vector A)
{
    return sqrt(Dot(A,A));
}
double Cross(Vector A,Vector B)
{
    return A.x*B.y-A.y*B.x;
}
Vector Rotate(Vector A,double rad)
{
    return Vector(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad));
}
bool InSegment(Point P,Point A,Point B)
{
    return dcmp(Cross(A-P,B-P))==0 && dcmp(Dot(A-P,B-P))<=0;
}
bool PointInPolygon(Point p,Point *poly,int n)
{
    int wn=0;
    for(int i=0;i<n;++i)
    {
        if(InSegment(p,poly[i],poly[(i+1)%n]) ) return true;
        int k=dcmp( Cross(poly[(i+1)%n]-poly[i], p-poly[i]) );
        int d1=dcmp( poly[i].y-p.y );
        int d2=dcmp( poly[(i+1)%n].y-p.y );
        if(k>0 && d1<=0 && d2>0) wn++;
        if(k<0 && d2<=0 && d1>0) wn--;
    }
    if(wn!=0) return true;
    return false;
}
double DistanceToSegment(Point P,Point A,Point B)
{
    if(A==B) return Length(A-P);
    Vector v1=B-A,v2=P-A,v3=P-B;
    if( dcmp(Dot(v1,v2))<0 ) return Length(v2);
    else if( dcmp(Dot(v1,v3))>0 ) return Length(v3);
    else return fabs(Cross(v1,v2))/Length(v1);
}
/***刘汝佳模板***/

const int maxn=50+5;

struct Square
{
    Point p[4];
    int id;
    double dist;
    bool operator<(const Square& rhs)const
    {
        return dist<rhs.dist || (dcmp(dist-rhs.dist)==0 && id<rhs.id);
    }
}sq[maxn];
Point P;

int main()
{
    int n;
    while(scanf("%d",&n)==1)
    {
        for(int i=0;i<n;++i)
        {
            Point p[4];
            scanf("%lf%lf%lf%lf",&p[0].x,&p[0].y,&p[2].x,&p[2].y);
            Point mid=Point( (p[0].x+p[2].x)/2, (p[0].y+p[2].y)/2 );//中点
            Vector v=Rotate(p[0]-p[2],PI/2)*0.5;//旋转后的对角线向量
            p[1]=mid+v;//点+向量位移==点
            p[3]=mid-v;//点+向量位移==点
            for(int j=0;j<4;j++)sq[i].p[j]=p[j];
            sq[i].dist=0;
            sq[i].id=i+1;
        }
        scanf("%lf%lf",&P.x,&P.y);
        for(int i=0;i<n;++i)//计算P点到每个正方形的距离
        {
            if(PointInPolygon(P,sq[i].p,4)) sq[i].dist=0;
            else
            {
                double min_dist=1e8;
                for(int j=0;j<4;++j)
                    min_dist = min(min_dist, DistanceToSegment(P,sq[i].p[j],sq[i].p[(j+1)%4]) );
                sq[i].dist=min_dist;
            }
        }
        sort(sq,sq+n);
        printf("%d",sq[0].id);
        for(int i=1;i<n;++i) printf(" %d",sq[i].id);
        printf("\n");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值