一种形象的理解是:我们用一根麻绳绑住一个外面的钉子(点), 然后拉着麻绳绕所有钉子一圈,这个麻绳最后也构成了点集的凸包。
这就是卷包裹法(Gift Wrapping)的思路
卷包裹算法从一个必然在凸包上的点开始向着一个方向依次选择最外侧的点,当回到最初的点时,所选出的点集就是所要求的凸包。这里还有两个问题不是很清楚:
1.怎么确定一个肯定在凸包上的点?
这个问题很好解决,取一个最左边的也就是横坐标最小的点(或最下边的点,纵坐标最小的),如果有多个这样的点, 就取这些点里纵坐标(横坐标)最小的。
2.如何确定下一个点(即最外侧的点)?
需要利用向量的叉积来解决这个问题
比如现在我们卷包裹卷到J点我们要选取一个最外侧的点,当然比较红色的到角可以直接得到最外侧的点,不过不方便,我们可以考虑那个蓝色的到角,利用向量 我们可以比较哪个点"更外侧"。比如点K和点I,我们利用向量JK乘以向量JI得到一个数,这个数应该是负数,说明I比K更外侧。两个向量的比较具有传递性,所以我们可以像N个数里取最大的数一样取出最外侧的。
遍历所有点,每个点都和现有最外侧的点比较,得到新的最外侧的点。
至此两个问题都得以解决 我们可以写出满足一般要求的卷包裹算法了,不过还遗留有一个问题 就是处理共线的问题。有时候我们需要凸包边上的点也考虑到,有时候却需要去掉这些点,我们通常称在凸包顶点处的点为极点,如果我们只要求保留极点而去除在边上的点,我们只需在取外侧的点的时候,碰到共线的点取最远的,相反 如果我们要保留所有在边上的点我们只需要在共线的点中取最近的。这样整个卷包裹法终于完成了:
下面是卷包裹算法解poj 1113的AC代码:
关于POJ 1113请参看:
http://128kj.iteye.com/blog/1748635
import java.util.*;
class point implements Comparable {//平面上的一个点
double x;
double y;
public int compareTo(Object o) {//按y升序排列,y相同按x升序
point b=(point)o;
if(this.y>b.y) return 1;
else if(this.y==b.y ){
if(this.x>b.x) return 1;
else if(this.x==b.x) return 0;
else return -1;
}
else return -1;
}
}
public class Main{
point[] A;//已知的平面上的点集
boolean[] F;//F[i]标记A[i]是否已在凸包中
Queue< Integer> Q=new LinkedList< Integer>();//点集A的凸包,
int n;
int l;
public Main(){
}
//向量ca与ba的叉积
double cross(point c,point a,point b) {
return (c.x-a.x)*(a.y-b.y)-(c.y-a.y)*(a.x-b.x);
}
//求距离
public double distance(point p1, point p2) {
return (Math.sqrt((p1.x - p2.x) * (p1.x- p2.x) + (p1.y - p2.y)* (p1.y - p2.y)));
}
//显示A
public void print(){
for(int i=0;i< A.length;i++){
System.out.println("["+A[i].x+","+A[i].y+"] ");
}
}
public void go(){
Scanner in=new Scanner(System.in);
n=in.nextInt();
l=in.nextInt();
A=new point[n+1];
F=new boolean[n+1];
for(int i=1;i<=n;i++){
A[i]=new point();
A[i].x=in.nextDouble();
A[i].y=in.nextDouble();
}
Arrays.sort(A,1,A.length-1);//注意这个排序从1开始
//确定一个肯定在凸包上的点
F[1]=true;//注意这里将A[1]标记为放进凸包,并不真正放进
int last=1;
while(true){
int Minn=-1;
for(int i=1;i<=n;i++) if(!F[i]) {//找一个不在凸包上的点
Minn=i;
break;
}
if(Minn==-1) break;//找不到,结束
for(int i=1;i<=n;i++) //遍历所有点, 每个点都和现有最外侧的点比较,得到新的最外侧的点
if((cross(A[last],A[i],A[Minn])>0)|| (cross(A[last],A[i],A[Minn]) == 0) &&
(distance(A[last], A[i]) > distance(A[last], A[Minn])))
Minn=i;
if(F[Minn]) break;//找不到最外侧的点了
Q.offer(Minn);//最外侧的点进凸包
F[Minn]=true;//标记这点已放进凸包了
last=Minn;
}
double ans=Math.PI*2*l;//计算圆周长
last=1;
Q.offer(1);//最后将A[1]放进凸包
while(!Q.isEmpty())//计算圆周长+凸包周长
{
int tmp=Q.poll();
ans+=Math.sqrt((A[last].x-A[tmp].x)*(A[last].x-A[tmp].x)
+(A[last].y-A[tmp].y)*(A[last].y-A[tmp].y));
last=tmp;
}
System.out.println((int)(ans + 0.5));
}
public static void main(String args[]){
Main ma=new Main();
ma.go();
}
}
本文图片和文字参照:
http://www.cnblogs.com/Booble/archive/2011/02/28/1967179.html
源码:
- 大小: 6.6 KB
- 大小: 8.2 KB
分享到:
相关推荐
【算法】Graham 凸包扫描算法 ( 凸包概念 | 常用的凸包算法 | 角排序 | 叉积 | Python 代码示例 ) https://hanshuliang.blog.csdn.net/article/details/139651095 博客源码快照 一、Graham 凸包扫描算法 1、凸包概念...
总结起来,"凸包练习: POJ 2187(JAVA)"是一个关于几何算法的实际应用问题,通过解决这个问题,你可以学习到如何用JAVA编程语言处理几何问题,掌握凸包算法,以及如何有效地读取、处理和输出数据。同时,这也是提升...
通过上述分类,我们可以看到 POJ 题目涵盖了算法与数据结构的多个方面,对于初学者来说是一份非常好的学习资料。掌握这些知识点不仅有助于提高解决问题的能力,也能为后续深入学习打下坚实的基础。
这篇博客“学习凸包(三): 凸包练习 POJ 1113”显然是关于如何通过编程解决凸包问题的一个实例。我们将深入探讨这个话题,主要关注凸包的定义、常见的求解算法以及如何用Java实现。 凸包可以被定义为一个给定集合中...
- **贪心算法**:适用于求解局部最优解的问题。 - **示例题目**: - POJ 3295: 贪心策略的应用 - **模拟**:对于一些可以直接通过步骤来解决问题的情况。 - **示例题目**: - POJ 1068: 模拟过程演示 - POJ ...
【标签】"POJ 1113 Wall 凸包"进一步明确了问题的核心,"POJ 1113"是该题目的编号,"Wall"可能是题目的具体情境,而"凸包"是解决问题的关键算法。 在计算机图形学和算法中,"凸包"是指一个点集的最小边界,这个边界...
求解凸包问题:输入是平面上 n 个点的集合 Q,凸包问题是要输出一个 Q 的 凸包。其中,Q 的凸包是一个凸多边形 P,Q 中的点或者在 P 上或者在 P 中。 实现基于枚举方法的凸包求解算法 实现基于 Graham-Scan 的凸包...
根据给定的信息,我们可以将这些知识点分为几个大类别:数据...以上是对经典POJ分类的详细解析,通过这些知识点的学习,可以帮助我们更好地理解和掌握算法与数据结构的基础知识,并能够应用于实际问题的解决过程中。
在给定的Java程序中,“计算几何求凸包算法的java实现”是解决这个问题的关键。 这个Java代码实现了对离散点集进行求解凸包的过程。在图形用户界面中,用户可以通过鼠标点击生成点,程序会实时地计算这些点的凸包并...
POJ 算法题目分类 POJ 算法题目分类是指分类所有 POJ 题目的算法思想和解决方案,本文将对算法分类进行详细的介绍。 一、基本算法 ...* 凸包:凸包是指解决问题的凸包算法,如 poj2187、poj1113。
这篇博客“学习凸包(一):暴力算法求解”主要介绍了如何使用基础的暴力算法来计算凸包。暴力算法,也称为蛮力法或全搜索法,是一种简单的但效率较低的解决问题的方法,它通常尝试所有可能的解决方案,直到找到一个...
最小凸包算法是一种在计算机科学中...总之,"最小凸包算法Java版"项目为学习和实践凸包算法提供了一个良好的起点。通过深入研究代码,我们可以不仅理解算法本身,还能掌握如何在实际项目中运用它,提升我们的编程技能。
**Melkman凸包算法详解** Melkman算法是一种在线算法,主要用于计算简单多边形的边界凸包。在计算机图形学、机器学习和数据结构领域,凸包问题是一个非常重要的概念,它可以帮助我们找到一组点中最外层的点集,这些...
分治法(Divide-and-Conquer)是计算机科学中最著名的算法设计策略之一,它将一个大问题分解成若干个规模较小、相同或相似的问题,然后递归地解决这些小问题,最后将小问题的解组合起来得到原问题的解。这一策略通常...
总之,"算法之凸包问题"的Java实现是一个结合了基础算法、数据结构和图形用户界面的综合性项目,它提供了一个实际应用计算机科学理论的实例,对于学习和理解凸包算法以及Java编程都有很大的帮助。
凸包算法是计算机科学中的一种重要算法,主要应用于图形学、机器学习、计算机视觉和几何计算等领域。在本项目中,我们关注的是如何通过界面化的方式实现这一算法,使用C++编程语言进行编码,并保证代码的可读性与...
文件"凸包-卡壳求最远距离.txt"很可能是包含了实现这个算法的源代码和详细注释。通过阅读和理解这段代码,你可以深入了解卡壳算法的实现细节,以及如何在实际问题中应用凸包算法来解决最远距离问题。学习并掌握这个...
graham求凸包算法 graham求凸包算法 graham求凸包算法 graham求凸包算法 graham求凸包算法 graham求凸包算法
- **示例题目**: POJ 2187, POJ 1113 - **注意事项**: 理解凸包算法的原理和实现过程。 ### 中级算法训练 #### 一、基本算法 **1. C++标准模板库的应用** - **定义**: 使用STL提供的容器、算法和迭代器等组件...