POJ 3608 Bridge Across Islands(求两凸包间的最小距离)

20 篇文章 0 订阅
4 篇文章 0 订阅
Bridge Across Islands
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 10108 Accepted: 2969 Special Judge

Description

Thousands of thousands years ago there was a small kingdom located in the middle of the Pacific Ocean. The territory of the kingdom consists two separated islands. Due to the impact of the ocean current, the shapes of both the islands became convex polygons. The king of the kingdom wanted to establish a bridge to connect the two islands. To minimize the cost, the king asked you, the bishop, to find the minimal distance between the boundaries of the two islands.

Input

The input consists of several test cases.
Each test case begins with two integers N, M. (3 ≤ N, M ≤ 10000)
Each of the next N lines contains a pair of coordinates, which describes the position of a vertex in one convex polygon.
Each of the next M lines contains a pair of coordinates, which describes the position of a vertex in the other convex polygon.
A line with N = M = 0 indicates the end of input.
The coordinates are within the range [-10000, 10000].

Output

For each test case output the minimal distance. An error within 0.001 is acceptable.

Sample Input

4 4
0.00000 0.00000
0.00000 1.00000
1.00000 1.00000
1.00000 0.00000
2.00000 0.00000
2.00000 1.00000
3.00000 1.00000
3.00000 0.00000
0 0

Sample Output

1.00000

Source



题目大意:

    给出两个凸包,求它们之间的最短距离。


解题思路:

    参考了大佬题解,代码都写的差不多了-_-b

    在第一个凸包P上找到最下方的点记作C,逆时针的下一个点记作A,在第二个凸包上找到最上方的点记作D,逆时针的下一个点记作B,然后我们不断旋转CA和DB,则最短距离一定就是某一时刻CA雨DB之间的距离。


AC代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
#define INF 0x3f3f3f3f
#define eps 1e-10

const int maxn=10000+3;

struct Point
{
    double x,y;
    Point(){}
    Point(double x,double y):x(x),y(y){}
    Point operator+(const Point &p)const
    {
        return Point(x+p.x,y+p.y);
    }
    Point operator-(const Point &p)const
    {
        return Point(x-p.x,y-p.y);
    }
    Point operator*(const double &d)
    {
        return Point(x*d,y*d);
    }
    bool operator<(const Point &a)const
    {
        if(x!=a.x)
            return x<a.x;
        else return y<a.y;
    }
    double dot(const Point &p)const//点乘
    {
        return x*p.x+y*p.y;
    }
    double det(const Point &p)const//叉乘
    {
        return x*p.y-y*p.x;
    }
};

Point P[maxn],Q[maxn];

//向量AB与AC的叉积,如果叉积大于0,那么C在向量AB的逆时针方向,叉积小于0则在AB的顺时针方向。如果叉积等于0,则ABC共线
inline double cross(const Point &A,const Point &B,const Point &C)
{
    return (B-A).det(C-A);
}

//向量AB与AC的点积,如果点积的结果为0,那么这两个向量互相垂直
inline double multi(const Point &A,const Point &B,const Point &C)
{
    return (B-A).dot(C-A);
}

//两点距离
inline double dist(const Point &A,const Point &B)
{
    return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

//逆时针排序
inline void anticlockwise_sort(Point *p,int N)
{
    for(int i=0;i<N-2;++i)
    {
        double tmp=cross(p[i],p[i+1],p[i+2]);
        if(tmp>eps)
            return;
        else if(tmp<-eps)
        {
            reverse(p,p+N);
            return;
        }
    }
}

//计算C点到线段AB的最短距离
inline double point_to_line(const Point &A,const Point &B,const Point &C)
{
    if(dist(A,B)<eps)
        return dist(B,C);
    if(multi(A,B,C)<-eps)
        return dist(A,C);
    if(multi(B,A,C)<-eps)
        return dist(B,C);
    return fabs(cross(A,B,C)/dist(A,B));
}

//求一条线段的两端点到另一条线段的距离,反过来一样,共4种情况
inline double line_to_line(const Point &A,const Point &B,const Point &C,const Point &D)
{
    return min(min(point_to_line(A,B,C),point_to_line(A,B,D)),min(point_to_line(C,D,A),point_to_line(C,D,B)));
}

double solve(Point *P,Point *Q,int n,int m)
{
    int yminP=0,ymaxQ=0;
    for(int i=0;i<n;++i)
        if(P[i].y<P[yminP].y)
            yminP=i;//P上y坐标最小的点
    for(int i=0;i<m;++i)
        if(Q[i].y>Q[ymaxQ].y)
            ymaxQ=i;//Q上y坐标最大的顶点
    P[n]=P[0];//为了方便避免求余
    Q[m]=Q[0];
    double arg,ans=INF;
    for(int i=0;i<n;++i)
    {
        while(arg=cross(P[yminP+1],Q[ymaxQ+1],P[yminP])-cross(P[yminP+1],Q[ymaxQ],P[yminP])>eps)//判断是否要继续移动ymaxQ
            ymaxQ=(ymaxQ+1)%m;
        ans=min(ans,line_to_line(P[yminP], P[yminP+1], Q[ymaxQ], Q[ymaxQ+1]));
        yminP=(yminP+1)%n;
    }
    return ans;
}

int main()
{
    int N,M;
    while(~scanf("%d%d",&N,&M)&&(N||M))
    {
        for(int i=0;i<N;++i)
            scanf("%lf%lf",&P[i].x,&P[i].y);
        for(int i=0;i<M;++i)
            scanf("%lf%lf",&Q[i].x,&Q[i].y);
        anticlockwise_sort(P,N);
        anticlockwise_sort(Q,M);
        printf("%.5f\n",solve(P,Q,N,M));
    }
    
    return 0;
}


评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值