题目:计算两个不相交凸多边形间的最小距离。

分析:计算几何、凸包、旋转卡壳。分别求出凸包,利用旋转卡壳求出对踵点对,枚举距离即可。

注意:1.利用向量法判断旋转,而不是计算角度;避免精度问题和TLE。

2.遇到平行线段时,需要计算4组点到线段距离,不然会漏掉对踵点对。

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cmath> using namespace std; //点结构
typedef struct pnode
{
double x,y,d;
pnode( double a, double b ) {x = a;y = b;}
pnode(){};
}point;
point T,P[10005],Q[10005]; //线段结构
typedef struct lnode
{
double x,y,dx,dy;
lnode( point a, point b ) {x = a.x;y = a.y;dx = b.x-a.x;dy = b.y-a.y;}
lnode(){};
}line; //叉乘 ab*ac
double crossproduct( point a, point b, point c )
{
return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
} //两点间距离
double dist( point a, point b )
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
} //点到线段距离
double dist( point a, point p, point q )
{
line l = line( p, q );
//判断垂足位置
if ( (l.dx*(p.x-a.x)+l.dy*(p.y-a.y))*(l.dx*(q.x-a.x)+l.dy*(q.y-a.y)) < 0 )
return fabs(l.dx*(a.y-l.y)-l.dy*(a.x-l.x))/sqrt(l.dx*l.dx+l.dy*l.dy);
else return min( dist( a, p ), dist( a, q ) );
} //坐标比较
bool cmp1( point a, point b )
{
return (a.x==b.x)?(a.y<b.y):(a.x<b.x);
} //级角比较
bool cmp2( point a, point b )
{
double cp = crossproduct( T, a, b );
if ( !cp ) return a.d < b.d;
else return cp > 0;
} //凸包
int graham( point* p, int n )
{
sort( p+0, p+n, cmp1 );
for ( int i = 1 ; i < n ; ++ i )
p[i].d = dist( p[0], p[i] );
T = p[0];
sort( p+1, p+n, cmp2 ); int top = 1;
for ( int i = 2 ; i < n ; ++ i ) {
while ( top > 0 && crossproduct( p[top-1], p[top], p[i] ) <= 0 ) -- top;
p[++ top] = p[i];
}
p[++ top] = p[0]; return top;
} //利用向量判断夹角
double judge( point a, point b, point c, point d )
{
return crossproduct( c, d, point( c.x+b.x-a.x, c.y+b.y-a.y ) );
} //旋转卡壳
double rotatingcalipers( point* p, point* q, int n, int m )
{
double D = 30000.0;
int R = 0;
for ( int i = 0 ; i < m ; ++ i )
if ( q[i].x >= q[R].x ) R = i;
for ( int L = 0 ; L < n ; ++ L ) {
while ( judge( p[L], p[L+1], q[R], q[R+1] ) < 1e-6 )
R = (R+1)%m;
//两条边平行时,需计算平行线段间最短距离,即四个点到线段的距离
D = min( min( D, dist( p[L], q[R] ) ),
min( min( dist( p[L], q[R], q[R+1] ), dist( q[R], p[L], p[L+1] ) ),
min( dist( p[L+1], q[R], q[R+1] ), dist( q[R+1], p[L], p[L+1] ) ) ) );
} return D;
} int main()
{
int N,M;
while ( scanf("%d%d",&N,&M) && N ) {
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); N = graham( P, N );
M = graham( Q, M ); printf("%.5lf\n",rotatingcalipers( P, Q, N, M ));
}
return 0;
}

最新文章

  1. 6_PHP AJAX MYSQL
  2. js正则匹配以固定格式结尾的字符串并匹配是手机访问,则跳转
  3. SpringHttpInvoker解析3-客户端实现
  4. CSS样式汇总
  5. Jenkins进阶系列之——06FTP publisher plugin插件下载(支持绝对路径)
  6. POJ 3267 The Cow Lexicon
  7. Delphi xe7 FireMonkey / Mobile (Android, iOS)生成 QR Code完整实例
  8. android——单点触控移动,多点触控放大缩小
  9. 转】MyEclipse使用总结——使用MyEclipse打包带源码的jar包
  10. IT技术开发人员35岁之前应该做的十件事
  11. 更改JENKINS主目录
  12. bootstrap栅格系统的div高度怎样定?
  13. python基础课程_2学习笔记3:图形用户界面
  14. A WPF/MVVM Countdown Timer
  15. MapReduce 规划 六系列 MultipleOutputs采用
  16. 【java API基本实现】ArrayList
  17. Oracle中session和processes的设置
  18. 移动端左右滑动问题-html与css解决
  19. JavaWeb三大组件之Servlet
  20. ROS入门学习

热门文章

  1. H5 required 改变错误提示oninvalid、oninput、onforminput
  2. 搭建LNMP发布ecshop系统及压测启用opcache缓存与否的情况
  3. c#自动更新+安装程序的制作 (转)
  4. MYSQL数据库备份与恢复【转】
  5. 两台主机打通ssh
  6. kill -9杀掉nginx主进程、reload失败解决办法
  7. 【转载】JavaEE权限管理分析
  8. uva 1400 - &quot;Ray, Pass me the dishes!&quot;
  9. OA学习笔记-008-岗位管理Action层实现
  10. Android开源项目发现---GridView 篇(持续更新)