ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

[软件构造] 凸包问题的简单算法

2021-06-02 02:05:16  阅读:201  来源: 互联网

标签:Point double 凸包 算法 Math 软件 public 向量


软件构造课作业
使用java有些许痛苦(bushi

目录

一、定义

对于一个集合D,所有包含D的凸集之交称为D的凸包。
用不严谨的话来讲,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边形,它能包含点集中所有的点。
举个例子:
对于下图这个含有12个点的点集
avatar
这个点集对应的凸包,就是下图中点\(p_1\),\(p_3\),\(p_7\),\(p_9\),\(p_{11}\),\(p_{12}\)所构成的凸多边形
avatar

二、算法

Gift-Wrapping算法

首先很显然,对于一个点集,它最左,最右,最上,最下的点一定在凸包上。

该算法要先找到点集中最左的(\(x\)坐标最小的)那个点,将它加入凸包并设为\(x\)。
然后将点\(x\)作为极坐标原点建立极坐标系,将点\(x\)分别与其他点\(p\)连线形成向量\(xp\),找到其中位于最右,即在其他每一个向量右边的向量(可以通过叉积判断),将这个向量中的\(p_i\)加入凸包,并且更新\(x\)为\(p_i\),再重复上述的步骤......
直到发现新的那个\(x\)点与最初的那个\(x\)坐标最小的点相同。

借上一部分的例子模拟一下算法的过程。
我们首次先找到\(x\)坐标最小的点\(p_1\),将它加入凸包并设为\(x\)。然后将点\(x\)分别与其他点\(p\)连线形成向量\(xp\),发现向量\(xp_3\)在最右边,所以将\(p_3\)加入凸包。
avatar
接下来更新\(x\)为\(p_3\),然后再次将点\(x\)分别与其他点\(p\)连线形成向量\(xp\),发现向量\(xp_7\)在最右边,所以将\(p_7\)加入凸包。
avatar
然后再更新\(x\)为\(p_7\),......
以此类推,直到\(x\)为\(p_{12}\)时,找到最右的向量为\(xp_1\),发现\(p_1\)就是最初的那个点,于是算法结束。

不难分析出该算法的复杂度应当是\(O(n^2)\)

三、模板题

Surround the Trees
题意:树林里有n棵树,给出这些树的坐标,想要用一根绳子将这些树都围起来,问绳子的最小长度。
分析:凸包模板题,答案是凸包周长
要注意当n==2时,只需要求两树之间的距离。(挺奇怪的,原题说是surrounding来着,还以为是两倍呢
(以及用java写题是真的痛苦。。。还是c好 = =

import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

public class Main {
    public static class Point {
        public double x;
        public double y;
        public Point(double x,double y) {
            this.x = x;
            this.y = y;
        }
    }
    public static double getlength(Point A , Point B) {
        return Math.sqrt(Math.pow(A.x - B.x , 2) + Math.pow(A.y - B.y , 2));
    }
    public static double cross(Point A , Point B) {
        return A.x * B.y - A.y * B.x;
    }
    public static double convexHull(Set<Point> points) {
        int n = points.size();
        if (n < 2) return 0;
        Set<Point> ans = new HashSet<Point>();
        double cr;
        Point a , fir ;
        Point o = new Point(Double.MAX_VALUE, Double.MAX_VALUE) ;
        //初始设置o点的x坐标为最大值
        for (Point b : points) {
            if (b.x < o.x ||  (b.x == o.x && b.y < o.y)) o = b;
        }//找点集里x坐标最小的一个点
        fir = o;//记录凸包中的第一个点
        double len = 0;
        do{
            ans.add(o);
            a = o;
            for (Point b : points){
                if (b == o) continue;
                if (a == o) {
                    a = b;//给a赋初值
                    continue;
                }//a点赋初值
                Point oa = new Point(a.x - o.x , a.y - o.y);
                Point ob = new Point(b.x - o.x , b.y - o.y);
                //向量oa和ob
                cr = cross(oa , ob);
                //叉积判断向量ob在向量0a的哪一边,若为负数则ob在oa右边
                if (cr < 0) a = b;
                else if (cr == 0 && (Math.abs(a.x - o.x) > Math.abs(b.x - o.x) || Math.abs(a.y - o.y) > Math.abs(b.y - o.y))) a = b;
                //当b点在oa连线上时,先考虑b点;否则先考虑a点
            }//求出点集中在o点最左边的点a
            len += getlength(o , a);
            o = a;
        }while (o != fir);
        if (n == 2) len = len / 2;
        return len;
    }
    public static void main(String []args) {
        Scanner scanner=new Scanner(System.in);
        int i , n;
        while (scanner.hasNext()) {
            n = scanner.nextInt();
            if (n == 0) return;
            Set<Point> set = new HashSet<Point>();
            for (i = 0 ; i < n ; i++)
            {
                Point p = new Point(scanner.nextDouble(),scanner.nextDouble()) ;
                set.add(p);
            }
            System.out.println(String.format("%.2f",convexHull(set)));
        }
    }
}

标签:Point,double,凸包,算法,Math,软件,public,向量
来源: https://www.cnblogs.com/lsykk/p/14839486.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有