题目地址:http://poj.org/problem?id=3608

解题思路:


注意:给出的点是按顺时针的,如果不是的话需要按照顺时针/逆时针排序

贴一下网上比较流行的原理解释:

1. 计算凸包P在y轴方向上的最小值记为yminP,和凸包Q在y轴方向上的最大值记为ymaxQ。
    2. 建立两条紧贴着yminP, ymaxQ的两条水平的直线LP, LQ。要求他们指向不同的方向。这时候他们就形成了一对anti-podal pair。
    3. 计算(yminP,ymaxQ)的距离,并记为minimum.
    4. 将两条直线顺时针旋转,直到其中一条遇到凸包的一条边停止。
    5. 只要有一条直线遇到了一条边,我们就需要计算新的vertex-vertex anti-podal之间的距离,并同minimum比较,并更新。如果两条直线都分同一条边重合,那么情况就复杂一些了。如果这两条边”重合“,也就是说我们可以画一条垂直于这两条直线的直线并且和凸包上的两个边都相交(不包括在顶点相交),那么我们就需要计算两条直线的距离了。否则的话我们只要计算3个新的顶点到顶点之间的距离。所有的具体都要同minimum比较,并更新minimum 的值。
    6. 重复步骤4,5,直到两条直线又回到起始位置为止。
    7. 输出最小的距离。
    
    # 之所以在最后旋转卡壳求2次是因为旋转卡壳要求两个直线都已经回到原点后才能结束。但是由于具体代码实现时,结束时不一定保证两条
      直线都已经回到原点(因为一个凸包的点数可能较多)。所以可以将两个凸包互换后再处理一次,就能保证正确性。
原文链接:https://blog.csdn.net/qq_29169749/article/details/58306965

但是原理是原理,代码实现起来我觉得不是很好理解,大概能半懂吧。当成模版来记吧。

核心代码中的这两行代码有点不太好理解,其实是用叉积代替了面积来计算,同底,叉积越大高越大,这个高就是点到线的垂直距离。之所以没有加fabs,一是避免超时,二是因为调用了两次这个函数,对最终结果并无影响。代码的时间复杂度看起来是O(n^2)级别的,实际上是线性的,while循环的次数很少。

while(Cross(v, ch2[miny+1]-ch1[maxy]) - Cross(v, ch2[miny]-ch1[maxy]) > eps)miny = (miny + 1) % m;

附一个简单样例,有利于搞懂程序:

5 4
0 1
3 4
4 2
3 1
2 0
4 6
6 7
8 5
6 4
0 0

ac代码:


#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
typedef long long ll;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int maxn = 1e4+10;
const double INF = 0x3f3f3f3f * 1.0;
int dcmp(double x)//精度三态函数(>0,<0,=0)
{if (fabs(x) < eps)return 0; //等于else return x < 0 ? -1 : 1;//小于,大于
}
struct Point
{double x,y;Point(double x=0,double y=0):x(x),y(y){}friend bool operator < (Point a, Point b){return a.x == b.x ? a.y < b.y : a.x < b.x;}friend bool operator == (Point a, Point b){return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;}
};
typedef Point Vector;
Vector operator + (Vector a, Vector 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);
}double Dot(Vector a, Vector b)//点积
{return a.x * b.x + a.y * b.y;
}
double Cross(Vector a, Vector b)//外积
{return a.x * b.y - a.y * b.x;
}
double Length(Vector a)//模
{return sqrt(Dot(a, a));
}double DistanceToSegment(Point P, Point A, Point B)//点P到AB所在线段的距离
{if(A == B) return Length(P - A);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);//三
}
double DistanceBetLines(Point A, Point B, Point C, Point D)
{double a = min(DistanceToSegment(A,C,D), DistanceToSegment(B,C,D));double b = min(DistanceToSegment(C,A,B), DistanceToSegment(D,A,B));return min(a, b);
}
double DistanceBetPolygons(Point ch1[], Point ch2[], int n, int m)
{double ans = INF;int maxy = 0, miny = 0;for(int i = 0; i < n; i++) if(ch1[i].y > ch1[maxy].y) maxy = i;for(int i = 0; i < m; i++) if(ch2[i].y < ch2[miny].y) miny = i;ch1[n] = ch1[0];ch2[m] = ch2[0];for(int i = 0; i < n; i++){Vector v = ch1[maxy+1] - ch1[maxy];while(Cross(v, ch2[miny+1]-ch1[maxy]) - Cross(v, ch2[miny]-ch1[maxy]) > eps)miny = (miny + 1) % m;ans = min(ans, DistanceBetLines(ch1[maxy], ch1[maxy+1], ch2[miny], ch2[miny+1]));maxy = (maxy + 1) % n;}return ans;
}
int n, m;
Point p1[maxn], p2[maxn];
int main()
{//freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);while(scanf("%d %d",&n, &m)){if(n == 0 && m == 0) break;for(int i = 0; i < n; i++) scanf("%lf %lf", &p1[i].x, &p1[i].y);for(int i = 0; i < m; i++) scanf("%lf %lf", &p2[i].x, &p2[i].y);printf("%.5lf\n", min(DistanceBetPolygons(p1, p2, n, m),DistanceBetPolygons(p2, p1, m, n)));}return 0;
}

【POJ3608】Bridge Across Islands(旋转卡壳求两凸多边形的最短间距)相关推荐

  1. POJ3608(旋转卡壳--求两凸包的最近点对距离)

    题目:Bridge Across Islands 分析:以下内容来自:http://blog.csdn.net/acmaker/article/details/3178696 考虑如下的算法, 算法的 ...

  2. Bridge Across Islands POJ - 3608 旋转卡壳求凸包最近距离

    \(\color{#0066ff}{题目描述}\) 几千年前,有一个小王国位于太平洋的中部.王国的领土由两个分离的岛屿组成.由于洋流的冲击,两个岛屿的形状都变成了凸多边形.王国的国王想建立一座桥来连接 ...

  3. Gym - 102460L Largest Quadrilateral(几何-凸包+旋转卡壳求最大的四边形面积)

    题目链接:点击查看 题目大意:在笛卡尔坐标系上给出 n 个点,要求选出四个点,使得组成的四边形面积最大,求出这个最大的面积,注意此处组成的四边形不是严格意义上的四边形,只需要选四个点就行 题目分析:首 ...

  4. bzoj1069: [SCOI2007]最大土地面积 凸包+旋转卡壳求最大四边形面积

    在某块平面土地上有N个点,你可以选择其中的任意四个点,将这片土地围起来,当然,你希望这四个点围成的多边形面积最大. 题解:先求出凸包,O(n)枚举旋转卡壳,O(n)枚举另一个点,求最大四边形面积 /* ...

  5. poj 3608 旋转卡壳求不相交凸包最近距离;

    题目链接:http://poj.org/problem?id=3608 #include<cstdio> #include<cstring> #include<cmath ...

  6. POJ - 2187 Beauty Contest (求距离最远点对-凸包+旋转卡壳/枚举 (旋转卡壳学习))

    链接:https://vjudge.net/problem/POJ-2187 题意:求求距离最远点对. 思路:肯定为凸包上的点,可枚举,也可根据凸包性质旋转卡壳求对踵点. 参考博客: https:// ...

  7. 旋转卡壳凸包(不用一下子就学完所有)

    目录 前言 参考博客 前置知识 1.极角排序 2.凸包(默认逆时针) 3.对踵点 旋转卡壳能解决的各类问题 1.计算距离 1.1凸多边形直径 1.2凸多边形宽 1.3凸多边形间最大距离 1.4凸多边形 ...

  8. poj 2187(旋转卡壳)

    传送门 模板题,求凸包,用旋转卡壳求出最远点对. 因为把int弄成double,WA了好几次,差点对idy大神给的模板失去信心...不过事实证明idy的写法没问题,orz! #include<c ...

  9. [HNOI2007]最小矩形覆盖(旋转卡壳)

    题意 给定一些点的坐标,要求求能够覆盖所有点的最小面积的矩形,输出所求矩形的面积和四个顶点坐标 题解 先求得一个凸包 可以知道对于凸包每一条边,其对应一个最小矩形覆盖,而凸包整体最小矩形覆盖在这个解之 ...

  10. hdu2202 凸包+旋转卡壳

    点击打开hdu2202 思路:最大三角形面积,那么肯定这三个点在最外围,所以先求凸包,然后用旋转卡壳求出那三个点求出面积最大. #include <iostream> #include & ...

最新文章

  1. RHCSA 解析-01
  2. threadlocal用法_ThreadLocal源码分析
  3. 使用容器与云计算技术快速进行深度学习
  4. Study on Android【五】--自定义ContentProvider的语义
  5. 漫步凸分析八——回收锥与无界
  6. gcn语义分割_语义分割该如何走下去?
  7. 炼丹手册——NaN值问题
  8. tomcat start 无法启动_解密Springboot内嵌Tomcat
  9. Linux版本的tomcat安装包
  10. Windows登录密码轻松破解
  11. 计算机知识考试试题及答案,职称计算机考试基础知识章节试题及答案一
  12. QComboBox样式表
  13. Qt之QTcpSocket 跨线程连续发送大数据
  14. flyway 实现 java 自动升级 SQL 脚本
  15. 电商平台大数据API大全
  16. android让字体左右对齐,Android 模仿微信读书文字左右对齐效果
  17. 计算机网络思维导图_计算机网络面试指南 考研/校招
  18. 20145324 《信息安全系统设计基础》第七周学习总结
  19. 【转】为什么程序猿996多猝屎,而企业家007却不会?
  20. 数据加解密时Base64异常:Illegal base64 character 3f

热门文章

  1. 国内外网站设计与浏览习惯的差异
  2. 【Linux】04 软链接和硬链接
  3. android 渲染 控件,自定义控件被忽略的渲染性能
  4. python如何预测双色球信息_python预测下一期双色球号码【机器学习】
  5. angular自带的一些api_在Angular软件中执行API请求的正确方式,了解一下
  6. 构建一个pool来管理无刷新页面的xmlhttp对象
  7. 全局变量在多个进程中不共享
  8. Configuration Manager 2012 R2系统需求
  9. java上路系列之一
  10. zephir-(1)开篇介绍