zoukankan      html  css  js  c++  java
  • poj3608Bridge Across Islands(旋转卡壳)

    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

    分析:
    用了一上午,终于A了
    题解:
    http://blog.csdn.net/acm_zl/article/details/12111657

    我在这里再进一步解释一下代码:
    这里写图片描述
    这是第一个复杂一点函数,把一个凸包中的所有点变成逆时针
    cross是叉积(sin),a–>b顺时针转结果是负,a–>b逆时针转结果是正

    这里写图片描述
    这里就是主体的计算部分了,想要强调的一点是,

    p[]是数组,传入的是指针,所以不用写取地址符就可以更改p的值

    这里写图片描述
    solve中的第一小部分,分别找p中最靠左的点和q中最靠右的点

    这里写图片描述
    这一部分是最难的了:
    一直奇怪为什么这里的Cross为什么不加fabs
    大概是因为我们进行了两遍solve,一定有一遍让两个三角形的面积都是两个逆时针转动的向量做Cross
    Cross逆时针转时值为正
    那么Cross(q[mq+1]-p[mp+1],p[mp]-p[mp+1])-Cross(q[mq]-p[mp+1],p[mp]-p[mp+1]))>eps
    表示mq+1代表的三角形面积大
    这里写图片描述
    跳出while循环的条件很明显是t<=eps
    如果t<-eps,说明卡壳的两条平行线一条与边重合,一条只过一点
    (为什么不是 < eps? 因为若两个面积相等,那么t < eps,但这种情况是要归到下面的)

    t==eps
    平行线恰好是两个多边形的边
    我们就把ta三个一组拆成上面的情况,
    最后返回最小值

    这里写图片描述
    点对边的情况

    dis传入的先是边的两个端点,之后是一个单点

    四种情况
    这里写图片描述

    这里写图片描述

    注意,dis传入的先是边的两个端点,之后是一个单点,所以ds在调用dis的时候不要传错参数

    这里写图片描述
    再多说一句,’==’也是可以重载的,返回值是bool

    这里写代码片
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    
    using namespace std;
    
    const double eps=1e-10;
    const double INF=1e10;
    int n,m;
    struct node{
        double x,y;
        node (double xx=0,double yy=0)
        {
            x=xx;y=yy;
        }
    };
    node p[10005],q[10005];
    
    double mn(double a,double b){return a>b?b:a;}
    int dcmp(double x)
    {
        if (fabs(x)<eps) return 0;
        else if (x>0) return 1;
        else return -1;
    }
    
    node operator +(const node &a,const node &b){return node(a.x+b.x,a.y+b.y);}
    node operator -(const node &a,const node &b){return node(a.x-b.x,a.y-b.y);}
    node operator *(const node &a,const double &b){return node(a.x*b,a.y*b);}
    node operator /(const node &a,const double &b){return node(a.x/b,a.y/b);}
    bool operator ==(const node &a,const node &b){
        return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
    }
    
    double Cross(node x,node y){return x.x*y.y-x.y*y.x;}
    double Dot(node x,node y){return x.x*y.x+x.y*y.y;}
    
    void red(node a[],int n,node b[],int m)
    {
        for (int i=0;i<n;i++) scanf("%lf%lf",&a[i].x,&a[i].y);
        for (int i=0;i<m;i++) scanf("%lf%lf",&b[i].x,&b[i].y);
    }
    
    void change(node a[],int b)
    {
        for (int i=0;i<b/2;i++)
        {
            node t=a[i];
            a[i]=a[b-i-1];
            a[b-i-1]=t;
        }
        return;
    }
    
    void work(node p[],int n,node q[],int m)
    {
        int i;
        for (i=0;i<n-2;i++)
            if (dcmp(Cross(p[i+1]-p[i],p[i+2]-p[i]))>0) break;   
            else if (dcmp(Cross(p[i+1]-p[i],p[i+2]-p[i]))<0)
            {
                change(p,n);
                break;
            }
        for (i=0;i<m-2;i++)
            if (dcmp(Cross(q[i+1]-q[i],q[i+2]-q[i]))>0) break;
            else if (dcmp(Cross(q[i+1]-q[i],q[i+2]-q[i]))<0)
            {
                change(q,m);
                break;
            }
    }
    
    double len(node a){return sqrt(Dot(a,a));}
    
    double dis(node a,node b,node p)
    {
        if (a==b) return len(a-p);
        node v1=b-a,v2=p-a,v3=p-b;
        if (dcmp(Dot(v1,v2))<0) return len(v2);
        if (dcmp(Dot(v1,v3))>0) return len(v3);
        return fabs(Cross(v1,v2))/len(v1);
    }
    
    double ds(node a,node b,node c,node d)
    {
        return mn(mn(dis(a,b,c),dis(a,b,d)),
                 mn(dis(c,d,a),dis(c,d,b)));
    }
    
    double solve(node p[],int n,node q[],int m)
    {
        int i,mp=0,mq=0;
        double ans=INF,t;
        for (i=0;i<n;i++)
            if (p[i].y<p[mp].y) mp=i;
        for (i=0;i<m;i++)
            if (q[i].y>q[mq].y) mq=i;
        p[n]=p[0];
        q[m]=q[0];
        for (i=0;i<n;i++)
        {
            while ((t=Cross(q[mq+1]-p[mp+1],p[mp]-p[mp+1])-Cross(q[mq]-p[mp+1],p[mp]-p[mp+1]))>eps)
                mq=(mq+1)%m;
            if (t<-eps) 
                ans=mn(ans,dis(p[mp],p[mp+1],q[mq]));
            else ans=mn(ans,ds(q[mq],q[mq+1],p[mp],p[mp+1]));
            mp=(mp+1)%n;
        }
        return ans;
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        while (n&&m)
        {
            red(p,n,q,m);
            work(p,n,q,m);
            double a,b;
            a=solve(p,n,q,m);
            b=solve(q,m,p,n);
            printf("%0.5lf
    ",mn(a,b));
            scanf("%d%d",&n,&m);
        }
        return 0;
    }
  • 相关阅读:
    .Netcore 2.0 Ocelot Api网关教程(7)- 限流
    .Netcore 2.0 Ocelot Api网关教程(6)- 配置管理
    .Netcore 2.0 Ocelot Api网关教程(5)- 认证和授权
    .Netcore 2.0 Ocelot Api网关教程(4)- 服务发现
    字符串方法集锦
    location下的属性集锦
    Js apply call方法详解
    所有事件event集锦
    移动端常用默认样式
    原生js的各种方法
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673428.html
Copyright © 2011-2022 走看看