阿里笔试模拟题,一个盒马鲜生送货员有一个送货的多边形区域,(x,y)为小广所在的位置,判断小广是否在送货区域内,如果不在计算小广到送货区域的距离?

有一个盒马鲜生送货员有一个送货的多边形(四边形)区域,(x,y)为小广所在的位置,判断小广是否在送货区域内,如果不在,计算小广到送货区域的最短距离?二维空间,忽略地球曲率。

输入:x,y 表示小广的位置坐标
输入:x1,y1,x2,y2,x3,y3,x4,y4表示多边形区域的顶点坐标

输出:如果小广在区域内返回 yes,0
如果小广不在区域内,返回 no,小广到送货区域的最短距离

测试用例:
输入:
1,1
0,0,0,2,2,2,2,0
输出yes,0


输入:
3,0
0,0,0,2,2,2,2,0
输出no,1


输入:
3,0
1,1,2,3,4,1,2,0
输出no,0.4472135954999576

代码如下:

import java.util.*;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String line = in.nextLine();
        //(x,y)为小广所在的位置
        double x = Double.parseDouble(line.split(",")[0]);
        double y = Double.parseDouble(line.split(",")[1]);
        line = in.nextLine();
        //xList记录了多边形n个点的x坐标,yList记录了多边形n个点的y坐标
        List<Double> xList = new ArrayList<>();
        List<Double> yList = new ArrayList<>();

        String[] array = line.split(",");
        for (int i = 0; i < array.length; i++) {
            xList.add(Double.parseDouble(array[i]));
            yList.add(Double.parseDouble(array[i + 1]));
            i++;
        }
        in.close();
        System.out.println(measureDistance(xList, yList, x, y));
    }

    public static String measureDistance(List<Double> xList, List<Double> yList, double x, double y) {
        //初始化多边形4个坐标
        Point A = new Point(xList.get(0), yList.get(0));
        Point B = new Point(xList.get(1), yList.get(1));
        Point C = new Point(xList.get(2), yList.get(2));
        Point D = new Point(xList.get(3), yList.get(3));
        boolean pointInRect = isPointInRect(A, B, C, D, x, y);
        if (pointInRect) {
            return "yes,0";
        } else {
            //说明x,y没在范围内,则算出该点与范围的最近距离
            String distance = getDistance(xList, yList, x, y);
            return "no," + distance;
        }
    }


    private static String getDistance(List<Double> xList1, List<Double> yList1, double x, double y) {
        double h1 = pointToLine(xList1.get(0), yList1.get(0), xList1.get(1), yList1.get(1), x, y);
        double h2 = pointToLine(xList1.get(1), yList1.get(1), xList1.get(2), yList1.get(2), x, y);
        double h3 = pointToLine(xList1.get(2), yList1.get(2), xList1.get(3), yList1.get(3), x, y);
        double h4 = pointToLine(xList1.get(3), yList1.get(3), xList1.get(0), yList1.get(0), x, y);
        double[] doubles = {h1, h2, h3, h4};
        Arrays.sort(doubles);
        //排序后找出最小距离
        return "" + doubles[0];
    }

    // 点到直线的最短距离的判断 点(x0,y0) 到由两点组成的线段(x1,y1) ,( x2,y2 )
    private static double pointToLine(double x1, double y1, double x2, double y2, double x0, double y0) {
        double space = 0;
        double a, b, c;
        a = lineSpace(x1, y1, x2, y2);// 线段的长度
        b = lineSpace(x1, y1, x0, y0);// (x1,y1)到点的距离
        c = lineSpace(x2, y2, x0, y0);// (x2,y2)到点的距离
        //点与线段两端的之一重合
        if (c <= 0.000001 || b <= 0.000001) {
            space = 0;
            return space;
        }
        //线段长度为0,点与线的长度变为点与点的
        if (a <= 0.000001) {
            space = b;
            return space;
        }
        //根据直角三角形的定理,判断哪个边长
        if (c * c >= a * a + b * b) {
            space = b;
            return space;
        }
        if (b * b >= a * a + c * c) {
            space = c;
            return space;
        }
        //锐角三角形时,用面积求高
        double p = (a + b + c) / 2;// 半周长
        double s = Math.sqrt(p * (p - a) * (p - b) * (p - c));// 海伦公式求面积
        space = 2 * s / a;// 返回点到线的距离(利用三角形面积公式求高)
        return space;
    }

    // 计算两点之间的距离
    private static double lineSpace(double x1, double y1, double x2, double y2) {
        double lineLength = 0;
        lineLength = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2)
                * (y1 - y2));
        return lineLength;
    }



//根据向量积正负判断点在图形内部
    private static boolean isPointInRect(Point A,Point B,Point C,Point D,double x, double y) {
        double a = (B.x - A.x) * (y - A.y) - (B.y - A.y) * (x - A.x);
        double b = (C.x - B.x) * (y - B.y) - (C.y - B.y) * (x - B.x);
        double c = (D.x - C.x) * (y - C.y) - (D.y - C.y) * (x - C.x);
        double d = (A.x - D.x) * (y - D.y) - (A.y - D.y) * (x - D.x);
        if ((a > 0 && b > 0 && c > 0 && d > 0) || (a < 0 && b < 0 && c < 0 && d < 0)) {
            return true;
        }
//      向量积(矢量)(x1,y1)X(x2,y2)=x1y2-x2y1
//      AB X AP = (b.x - a.x, b.y - a.y) x (p.x - a.x, p.y - a.y) = (b.x - a.x) * (p.y - a.y) - (b.y - a.y) * (p.x - a.x);
//      BC X BP = (c.x - b.x, c.y - b.y) x (p.x - b.x, p.y - b.y) = (c.x - b.x) * (p.y - b.y) - (c.y - b.y) * (p.x - b.x);
        return false;
    }
}

class Point {
    //坐标类
    public double x;
    public double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值