js实现凸包问题

背景:

地图上给出若干个点,求出这些点围绕的最大面积,并按顺序排列。

原理:
暴力枚举,由反证法得x轴最小的值一定是围绕的边界点,将其作为起点,在寻找下一个点符合其余的点均在这两个点构成直线的一侧。最后回到初始点时返回。

向量和点关系算法:

S(P1,P2,P3)=|y1 y2 y3|= (x1-x3)*(y2-y3)-(y1-y3)*(x2-x3)

当P1P2P3逆时针时S为正的,当P1P2P3顺时针时S为负的。

因为坐标经度需求大,为了精确计算使用了函数实现四则运算。

function mul(a, b) {
  var c = 0,
    d = a.toString(),
    e = b.toString();
  try {
    c += d.split(".")[1].length;
  } catch (f) {}
  try {
    c += e.split(".")[1].length;
  } catch (f) {}
  return (
    (Number(d.replace(".", "")) * Number(e.replace(".", ""))) / Math.pow(10, c)
  );
}
function sub(a, b) {
  var c, d, e;
  try {
    c = a.toString().split(".")[1].length;
  } catch (f) {
    c = 0;
  }
  try {
    d = b.toString().split(".")[1].length;
  } catch (f) {
    d = 0;
  }
  return (e = Math.pow(10, Math.max(c, d))), (mul(a, e) - mul(b, e)) / e;
}

输入数据结构示例:
lines[{x:"123",y:"456"},{x:"123",y:"456"}]

具体实现:

 //范围算法
    ConvexHull(lines) {
      //排序去重
      for (let i = 0; i < lines.length; i++) {
        for (let j = 0; j < lines.length - i - 1; j++) {
          if (lines[j].x > lines[j + 1].x) {
            let tamp = lines[j];
            lines[j] = lines[j + 1];
            lines[j + 1] = tamp;
          }
          if (lines[j].x == lines[j + 1].x && lines[j].y == lines[j + 1].y) {
            lines.splice(j + 1, 1);
            j--;
          }
        }
      }
      let result = [];
      let index = 1;
      result.push(lines[0]);
      while (true) {
        let point = this.findNext(lines, result[index - 2], result[index - 1]);
        if (point == null) break;
        result.push(point);
        if (point.x == lines[0].x && point.y == lines[0].y) {
          break;
        }
        if (index > lines.length + 2) {
          break;
        }
        index++;
      }
      return result;
    },
   findNext(lines, start, node) {
      for (let i = 0; i < lines.length; i++) {
        if (start != null && start.x == lines[i].x && start.y == lines[i].y) {
          continue;
        }
        if (node != null && node.x == lines[i].x && node.y == lines[i].y) {
          continue;
        }
        let search = true;
        let target = -9999;
        for (let j = 0; j < lines.length; j++) {
          if (i == j) continue;
          if (node != null && node.x == lines[j].x && node.y == lines[j].y) {
            continue;
          }
          let left =
            sub(node.x, lines[j].x) * sub(lines[i].y, lines[j].y) -
              sub(node.y, lines[j].y) * sub(lines[i].x, lines[j].x) >
            0
              ? true
              : false;
          if (target == -9999) {
            target = left;
          }
          if (left != target) {
            search = false;
            break;
          }
        }
        if (search == true) {
          return lines[i];
        }
      }
    },

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现凸包问题的蛮力法,需要以下步骤: 1.定义点类,表示平面上的一个点,包括横坐标和纵坐标。 2.定义凸包类,实现凸包问题的蛮力解法。 3.实现凸包类的构造方法,传入一个点集合。 4.实现凸包类的计算凸包方法,利用双重循环遍历点集合,找出凸包上的点。 5.实现凸包类的可视化方法,将计算出的凸包用图形展示出来。 下面是一个简单的Java代码示例,实现凸包问题的蛮力解法可视化: ``` import java.awt.*; import java.util.ArrayList; import java.util.List; import javax.swing.*; public class ConvexHull extends JPanel { // 定义点类 private class Point { double x, y; public Point(double x, double y) { this.x = x; this.y = y; } } // 定义凸包类 private class Hull { List<Point> points = new ArrayList<Point>(); public Hull(List<Point> points) { this.points = points; } public List<Point> calculate() { List<Point> hull = new ArrayList<Point>(); int n = points.size(); for (int i = 0; i < n; i++) { for (int j = i+1; j < n; j++) { boolean flag = true; Point p1 = points.get(i), p2 = points.get(j); for (int k = 0; k < n; k++) { if (k == i || k == j) continue; Point p = points.get(k); if (cross(p1, p2, p) < 0) { flag = false; break; } } if (flag) { if (!hull.contains(p1)) hull.add(p1); if (!hull.contains(p2)) hull.add(p2); } } } return hull; } private double cross(Point p1, Point p2, Point p) { return (p2.x-p1.x)*(p.y-p1.y)-(p2.y-p1.y)*(p.x-p1.x); } } // 画出凸包 public void paint(Graphics g) { super.paint(g); Graphics2D g2d = (Graphics2D) g; List<Point> points = new ArrayList<Point>(); points.add(new Point(100, 100)); points.add(new Point(200, 50)); points.add(new Point(300, 100)); points.add(new Point(250, 200)); points.add(new Point(150, 200)); points.add(new Point(50, 150)); Hull hull = new Hull(points); List<Point> hullPoints = hull.calculate(); int[] xPoints = new int[hullPoints.size()]; int[] yPoints = new int[hullPoints.size()]; for (int i = 0; i < hullPoints.size(); i++) { xPoints[i] = (int) hullPoints.get(i).x; yPoints[i] = (int) hullPoints.get(i).y; } g2d.drawPolygon(xPoints, yPoints, hullPoints.size()); } // 主函数 public static void main(String[] args) { JFrame frame = new JFrame("Convex Hull"); frame.add(new ConvexHull()); frame.setSize(400, 400); frame.setLocationRelativeTo(null); frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } } ``` 在这个例子中,我们随意定义了一个点集合,包含六个点,然后利用凸包类计算出凸包,最后将凸包用多边形图形展示出来。你可以根据自己的需要修改点集合,或者将点集合通过参数传入。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值