惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threat Research - Cisco Blogs
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
月光博客
月光博客
V
Vulnerabilities – Threatpost
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
S
Secure Thoughts
Microsoft Azure Blog
Microsoft Azure Blog
Blog — PlanetScale
Blog — PlanetScale
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
T
Tailwind CSS Blog
S
SegmentFault 最新的问题
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
云风的 BLOG
云风的 BLOG
The Last Watchdog
The Last Watchdog
L
LINUX DO - 热门话题
酷 壳 – CoolShell
酷 壳 – CoolShell
WordPress大学
WordPress大学
AWS News Blog
AWS News Blog
美团技术团队
G
Google Developers Blog
宝玉的分享
宝玉的分享
www.infosecurity-magazine.com
www.infosecurity-magazine.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
Recent Commits to openclaw:main
Recent Commits to openclaw:main
I
InfoQ
小众软件
小众软件
Google DeepMind News
Google DeepMind News
P
Privacy & Cybersecurity Law Blog
Stack Overflow Blog
Stack Overflow Blog
Webroot Blog
Webroot Blog
D
DataBreaches.Net
IT之家
IT之家
PCI Perspectives
PCI Perspectives
人人都是产品经理
人人都是产品经理
Hacker News: Ask HN
Hacker News: Ask HN
L
LangChain Blog
SecWiki News
SecWiki News
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Cisco Blogs
T
Threatpost
P
Proofpoint News Feed
Y
Y Combinator Blog
Cloudbric
Cloudbric
T
Tor Project blog
量子位
博客园_首页
B
Blog
Hugging Face - Blog
Hugging Face - Blog
GbyAI
GbyAI
D
Darknet – Hacking Tools, Hacker News & Cyber Security

博客园 - woodfish

偏序集的Dilworth定理 XJOJ历经2个月终于完成啦~~ fork()调用的一个趣题 实现google那种输入框提示的功能 POJ 3691 安徽第二题 有限状态自动机+DP 哈尔滨赛区网络预选赛总结 [计算几何]点集中的点能组成多少个正方形 [计算几何]POJ 1375 点对圆的切线+线段重叠 [计算几何]POJ 1556 判断线段相交+Dijkstra [计算几何] POJ 1873 暴力+凸包 [计算几何]POJ 1266 三角形的外接圆 圆的参数方程 POJ 1026 置换群 [计算几何]POJ 1031 计算点对多边形的偏转角度 [计算几何]POJ2079 求点集中面积最大的三角形 [计算几何]凸包的旋转卡壳算法 C++禁止一个类被继承的技术 C与汇编的接口技术 计算位数的3种方法 避免使用条件分支
[计算几何]POJ3608 求2个不相交凸包的最短距离
woodfish · 2008-09-01 · via 博客园 - woodfish

http://acm.pku.edu.cn/JudgeOnline/problem?id=3608

本题要求不相交凸包的最短距离,可以利用旋转卡壳算法来做。首先让2个凸包的点都按逆时针方向排列,然后找出第一个凸包的y坐标最小的点a,第二个凸包的y坐标最大的点b,然后在a,b上做一条与x轴平行的直线,可以证明最短距离只有可能在这2条平行线之间取得。下面的工作就是沿着凸包来旋转这2条平行线了,在旋转的过程中记录最小值。

具体说明在http://cgm.cs.mcgill.ca/~orm/mind2p.html

 

  1. Compute the vertex with minimum y coordinate for P (call it yminP) and the vertex with maximum y coordinate for Q (call it ymaxQ).
  2. Construct two lines of support LP and LQ for the polygons at yminP and ymaxQ such that the polygons lie to the right of their respective lines of support. Then LP and LQ have opposite direction, and yminP and ymaxQ form an anti-podal pair between the polygons.
  3. Compute dist(yminP,ymaxQ) and keep it as the minimum.
  4. Rotate the lines clockwise until one of them coincides with an edge of its polygon.
  5. If only one line coincides with an edge, then the vertex-edge anti-podal pair distance should be computed along with the new vertex-vertex anti-podal pairA distance. Both distances are compared the current minimum, which is updated if necessary. If both lines of support coincide with edges, then the situation is somewhat more complex. If the edges "overlap", that is if one can construct a line perpendicular to both edges and intersecting both edges (but not at vertices), then the edge-edge distance should be computed. Otherwise the three new vertex-vertex anti-podal pair distances are computed. All distances are compared to the current minimum which is updated if necessary.
  6. Repeat steps 4 and 5, until the lines reach (yminP, ymaxQ) again.
  7. Output the minimum distance.

在具体实现的过程中,有2点要特别小心:

1.旋转角度的处理。

2.计算2条平行线之间的最短距离最容易出错,要想清楚最短距离到底是什么。

//poj 3608
//author: chenkun
//旋转卡壳
#include <stdio.h>
#include 
<math.h>const int maxn=10010;
const double eps=1.0e-6;
const double pi=acos(-1.0);
const double inf=1.0e250;struct Point {
    
double x,y;
};
struct Poly {
    
int n;
    Point p[maxn];
};
Poly po1,po2;

inline 

double min(double a,double b) {return a<b?a:b;}
inline 
double mydist(Point p1,Point p2) {
    
return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}
double Area(Poly *po) {
    
double area=0;
    
for(int i=1;i<=po->n;i++) {
        area
+=(po->p[i-1].x*po->p[i%po->n].y-po->p[i%po->n].x*po->p[i-1].y);
    }
    
return area/2;
}
void changeClockwise(Poly *po) {
    Point tmp;
    
for(int i=0;i<=(po->n-1)/2;i++) {
        tmp
=po->p[i];
        po
->p[i]=po->p[po->n-1-i];
        po
->p[po->n-1-i]=tmp;
    }
}
double angle(Point p1,Point p2,double tangle) {
    
double ang,tmp;
    Point p;
    p.x
=p2.x-p1.x;
    p.y
=p2.y-p1.y;
    
if(fabs(p.x)<eps) {
        
if(p.y>0) ang=pi/2;
        
else ang=3*pi/2;
    }
else{
        ang
=atan(p.y/p.x);
        
if(p.x<0) ang+=pi;
    }
    
while(ang<0) ang+=2*pi;
    
if(ang>=pi) tangle+=pi;
    
if(ang>tangle) tmp=ang-tangle;
    
else tmp=pi-(tangle-ang);
    
while(tmp>=pi) tmp-=pi;
    
if(fabs(tmp-pi)<eps) tmp=0;
    
return tmp;
}
double disPointToSeg(Point p1,Point p2,Point p3) {
    
double a=mydist(p1,p2);
    
double b=mydist(p1,p3);
    
double c=mydist(p2,p3);
    
if(fabs(a+b-c)<eps) return 0;
    
if(fabs(a+c-b)<eps||fabs(b+c-a)<eps) return min(a,b);
    
double t1=b*b+c*c-a*a;
    
double t2=a*a+c*c-b*b;
    
if(t1<=0||t2<=0return min(a,b);double area=(p3.x-p1.x)*(p2.y-p1.y)-(p2.x-p1.x)*(p3.y-p1.y);
    
return fabs(area)/(c);
}

inline 

double disPallSeg(Point p1,Point p2,Point p3,Point p4) {
    
return min(min(disPointToSeg(p1,p3,p4),disPointToSeg(p2,p3,p4)),min(disPointToSeg(p3,p1,p2),disPointToSeg(p4,p1,p2)));
}
bool init() {
    scanf(
"%d %d",&po1.n,&po2.n);
    
if(po1.n==0&&po2.n==0return false;
    
for(int i=0;i<po1.n;i++) {
        scanf(
"%lf %lf",&po1.p[i].x,&po1.p[i].y);
    }
    
for(int i=0;i<po2.n;i++) {
        scanf(
"%lf %lf",&po2.p[i].x,&po2.p[i].y);
    }
    
return true;
}
int main() {
    
//freopen("in.txt","r",stdin);
    while(init()) {
        
if(Area(&po1)<0) changeClockwise(&po1);
        
if(Area(&po2)<0) changeClockwise(&po2);
        
double ymin=inf,ymax=-inf;
        
int k1,k2;
        
for(int i=0;i<po1.n;i++)
            
if(po1.p[i].y<ymin) {
                ymin
=po1.p[i].y;
                k1
=i;
            }
        
for(int i=0;i<po2.n;i++)
            
if(po2.p[i].y>ymax) {
                ymax
=po2.p[i].y;
                k2
=i;
            }
        
double langle=0;
        
double angle1,angle2;
        
double ans=inf;
        
double slope=0;
        
while(slope<=140) {
            
while(langle>=pi) langle-=pi;
            
if(fabs(pi-langle)<eps) langle=0;
            angle1
=angle(po1.p[k1],po1.p[(k1+1)%po1.n],langle);
            angle2
=angle(po2.p[k2],po2.p[(k2+1)%po2.n],langle);
            
if(fabs(angle1-angle2)<eps) {
                
double d=disPallSeg(po1.p[k1],po1.p[(k1+1)%po1.n],po2.p[k2],po2.p[(k2+1)%po2.n]);
                
if(d<ans) ans=d;
                k1
=(k1+1)%po1.n;
                k2
=(k2+1)%po2.n;
                langle
+=angle1;
                slope
+=angle1;
            }
else if(angle1<angle2) {
                
double d=disPointToSeg(po2.p[k2],po1.p[k1],po1.p[(k1+1)%po1.n]);
                
if(d<ans) ans=d;
                k1
=(k1+1)%po1.n;
                langle
+=angle1;
                slope
+=angle1;
            }
else{
                
double d=disPointToSeg(po1.p[k1],po2.p[k2],po2.p[(k2+1)%po2.n]);
                
if(d<ans) ans=d;
                k2
=(k2+1)%po2.n;
                langle
+=angle2;
                slope
+=angle2;
            }
        }
        printf(
"%.5lf\n",ans);
    }
    
return 0;
}