题目链接:http://poj.org/problem?id=3608

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<cmath>
  4. #include<iostream>
  5. #include<algorithm>
  6. #include<queue>
  7. using namespace std;
  8. const int maxn = ;
  9. const int maxe = ;
  10. const int INF = 0x3f3f3f;
  11. const double eps = 1e-;
  12. const double PI = acos(-1.0);
  13.  
  14. struct Point{
  15. double x,y;
  16. Point(double x=, double y=) : x(x),y(y){ } //构造函数
  17. };
  18. typedef Point Vector;
  19.  
  20. Vector operator + (Vector A , Vector B){return Vector(A.x+B.x,A.y+B.y);}
  21. Vector operator - (Vector A , Vector B){return Vector(A.x-B.x,A.y-B.y);}
  22. Vector operator * (Vector A , double p){return Vector(A.x*p,A.y*p);}
  23. Vector operator / (Vector A , double p){return Vector(A.x/p,A.y/p);}
  24.  
  25. bool operator < (const Point& a,const Point& b){
  26. return a.x < b.x ||( a.x == b.x && a.y < b.y);
  27. }
  28.  
  29. int dcmp(double x){
  30. if(fabs(x) < eps) return ;
  31. else return x < ? - : ;
  32. }
  33. bool operator == (const Point& a, const Point& b){
  34. return dcmp(a.x - b.x) == && dcmp(a.y - b.y) == ;
  35. }
  36.  
  37. ///向量(x,y)的极角用atan2(y,x);
  38. double Dot(Vector A, Vector B){ return A.x*B.x + A.y*B.y; }
  39. double Length(Vector A) { return sqrt(Dot(A,A)); }
  40. double Angle(Vector A, Vector B) { return acos(Dot(A,B) / Length(A) / Length(B)); }
  41. double Cross(Vector A, Vector B) { return A.x*B.y - A.y * B.x; }
  42.  
  43. Vector Rotate(Vector A, double rad) { return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad)); }
  44.  
  45. ///求点P到线段AB的距离,先看Q点在线段外还是内;利用点积就可以,
  46. double DistanceToSegment(Point P,Point A,Point B){
  47. if(A == B) return Length(P-A);
  48. Vector v1 = B - A,v2 = P - A,v3 = P - B;
  49. if(dcmp(Dot(v1,v2)) < ) return Length(v2);
  50. else if(dcmp(Dot(v1,v3) > )) return Length(v3);
  51. else return fabs(Cross(v1,v2))/Length(v1);
  52. }
  53. ///求线段AB与线段CD的距离;
  54. double DistanceBetweenSegment(Point A,Point B,Point C,Point D){
  55. return min(min(DistanceToSegment(A,C,D),DistanceToSegment(B,C,D)),min(DistanceToSegment(C,A,B),DistanceToSegment(D,A,B)));
  56. }
  57.  
  58. //凸包:
  59. /**Andrew算法思路:首先按照先x后y从小到大排序(这个地方没有采用极角逆序排序,所以要进行两次扫描),删除重复的点后得到的序列p1,p2.....,然后把p1和p2放到凸包中。从p3开始,当新的
  60. 点在凸包“前进”方向的左边时继续,否则依次删除最近加入凸包的点,直到新点在左边;**/
  61.  
  62. //Goal[]数组模拟栈的使用;
  63. int ConvexHull(Point* P,int n,Point* Goal){
  64. sort(P,P+n);
  65. int m = unique(P,P+n) - P; //对点进行去重;
  66. int cnt = ;
  67. for(int i=;i<m;i++){ //求下凸包;
  68. while(cnt> && dcmp(Cross(Goal[cnt-]-Goal[cnt-],P[i]-Goal[cnt-])) <= ) cnt--;
  69. Goal[cnt++] = P[i];
  70. }
  71. int temp = cnt;
  72. for(int i=m-;i>=;i--){ //逆序求上凸包;
  73. while(cnt>temp && dcmp(Cross(Goal[cnt-]-Goal[cnt-],P[i]-Goal[cnt-])) <= ) cnt--;
  74. Goal[cnt++] = P[i];
  75. }
  76. if(cnt > ) cnt--; //减一为了去掉首尾重复的;
  77. return cnt;
  78. }
  79.  
  80. double solve(Point* P1,Point* Q1,int Minid,int Maxid,int N,int M){
  81. double temp,ret = 1e5;
  82. P1[N] = P1[]; Q1[M] = Q1[];
  83. for(int i=;i<N;i++){
  84. while(temp = dcmp(Cross(Q1[Maxid]-Q1[Maxid+],P1[Minid+]-P1[Minid]))> ) //这一步最难理解:要理解怎样才能使Q1[Maxid]Q1[Maxid+1]这条线段最接近线段P1[Minid+1]P1[Minid];
  85. Maxid = (Maxid+)%M; // 先以P1[Minid]为定点,旋转Q1[Maxid];
  86. if(temp < ) ret = min(ret,DistanceToSegment(Q1[Maxid],P1[Minid],P1[Minid+]));
  87. else ret = min(ret,DistanceBetweenSegment(P1[Minid],P1[Minid+],Q1[Maxid],Q1[Maxid+]));\
  88. Minid = (Minid + )%N; //再旋转P1[Minid];
  89. }
  90. return ret;
  91. }
  92. Point read_point(){
  93. Point A;
  94. scanf("%lf %lf",&A.x,&A.y);
  95. return A;
  96. }
  97.  
  98. /*******************************分割线******************************/
  99. Point P[maxn],Q[maxn];
  100. Point P1[maxn],Q1[maxn]; //利用凸包算法使坐标逆时针化后的存储;
  101. int N,M;
  102. int Maxid,Minid;
  103.  
  104. void GetMaxandMin(int& Maxid,int& Minid){
  105. Maxid = ; Minid = ;
  106. for(int i=;i<N;i++){
  107. if(P1[i].y < P1[Minid].y) Minid = i;
  108. }
  109. for(int i=;i<M;i++){
  110. if(Q1[i].y > Q1[Maxid].y) Maxid = i;
  111. }
  112. }
  113.  
  114. int main()
  115. {
  116. //freopen("E:\\acm\\input.txt","r",stdin);
  117.  
  118. while(cin>>N>>M && N+M){
  119. for(int i=;i<N;i++) P[i] = read_point();
  120. N = ConvexHull(P,N,P1);
  121.  
  122. for(int i=;i<M;i++) Q[i] = read_point();
  123. M = ConvexHull(Q,M,Q1);
  124.  
  125. GetMaxandMin(Maxid,Minid);
  126.  
  127. double ans = solve(P1,Q1,Minid,Maxid,N,M);
  128. printf("%.5f\n",ans);
  129. }
  130. }

poj 3608 旋转卡壳求不相交凸包最近距离;的更多相关文章

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

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

  2. poj 3608(旋转卡壳求解两凸包之间的最短距离)

    Bridge Across Islands Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9768   Accepted: ...

  3. 「POJ-3608」Bridge Across Islands (旋转卡壳--求两凸包距离)

    题目链接 POJ-3608 Bridge Across Islands 题意 依次按逆时针方向给出凸包,在两个凸包小岛之间造桥,求最小距离. 题解 旋转卡壳的应用之一:求两凸包的最近距离. 找到凸包 ...

  4. POJ 3608 旋转卡壳

    思路: 旋转卡壳应用 注意点&边  边&边  点&点 三种情况 //By SiriusRen #include <cmath> #include <cstdi ...

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

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

  6. POJ2187 旋转卡壳 求最长直径

    给定平面上的一些散点集,求最远两点距离的平方值. 题解: 旋转卡壳求出凸包,然后根据单调性,求出最远两点的最大距离 #pragma GCC optimize(2) #pragma G++ optimi ...

  7. POJ 2187 Beauty Contest【旋转卡壳求凸包直径】

    链接: http://poj.org/problem?id=2187 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=22013#probl ...

  8. poj 2187 Beauty Contest , 旋转卡壳求凸包的直径的平方

    旋转卡壳求凸包的直径的平方 板子题 #include<cstdio> #include<vector> #include<cmath> #include<al ...

  9. UVa 1453 - Squares 旋转卡壳求凸包直径

    旋转卡壳求凸包直径. 参考:http://www.cppblog.com/staryjy/archive/2010/09/25/101412.html #include <cstdio> ...

随机推荐

  1. Notepad++在编程使用时的小技巧

    http://blog.csdn.net/freewaywalker/article/details/8010790 为了编程时更快捷和适应个人习惯,我们可以对Notepad++进行一系列的设置,这当 ...

  2. Initializer block.

    Ref: Initializing Fields Instance initializers are permitted to refer to the current object via the ...

  3. offie2010设置前两页和后面显示不同页码的方法

    1.在需要设置的第二页文档后面点击一下,让光标进入,再菜单上找到"页面布局"—“分栏符”—“下一页”(如图) 2.插入—页码—页面底端(如图) 3.点击页码附近的—“链接到前一页面 ...

  4. phpcms v9后台美化需要修改的部分整理

    PHPcms后台登陆后的页面修改 Phpcms->modules->admin->templates->main.tpl.php 1,安全提示部分 <h6>< ...

  5. lmsw - 加载机器状态字

    将源操作数加载到机器状态字,即寄存器 CR0 的位 0 到 15.源操作数可以是 16 位通用寄存器或内存位置.只有源操作数的低 4 位(也就是 PE.MP.EM 及 TS 标志)会加载到 CR0.C ...

  6. ThinkPHP框架下,jq实现在div中添加标签并且div的大小会随之变化

    php初学者,有什么不对的还请指正. 首先是在html页面中用jq实现添加标签:divAchivePersonnal是select所在的div的外层div,divselectAchivePersonn ...

  7. php 获取域名的whois 信息

    首先先了解几个文件操作函数: fwrite() 函数写入文件(可安全用于二进制文件). fwrite() 把 string 的内容写入文件指针 file 处. 如果指定了 length,当写入了 le ...

  8. JSP语法

    第3章  JSP语法 [本章专家知识导学] JSP是建立在Java语言基础上的一种Web程序设计语言,具有自己特有的用法和指令.本章首先介绍JSP页面的程序结构,然后讲述JSP程序中经常用到基本的面向 ...

  9. JS拖动div的原理

    要实现移动窗体,首先要捕获三个参数:1.a = 鼠标点击时的坐标.2.b = 被移动窗体的左顶点坐标.3.c = 鼠标移动时的坐标.然后还要算出你鼠标无论点击窗体哪个位置,移动改变的都是 (d = 窗 ...

  10. MySQL ubuntu启动

    service mysql start 启动 service mysql restart 重启 service mysql stop 停止 mysql -uroot -ppassword 登入mysq ...