2018 秋招 阿里巴巴 笔试测验题 送快递的最短路线

送快递的最短路线

题目描述:

    某物流派送员p,需要给a、b、c、d4个快递点派送包裹,请问派送员需要选择什么的路线,才能完成最短路程的派送。假设如图派送员的起点坐标(0,0),派送路线只能沿着图中的方格边行驶,每个小格都是正方形,且边长为1,如p到d的距离就是4。随机输入n个派送点坐标,求输出最短派送路线值(从起点开始完成n个点派送并回到起始点的距离)。

思路:

    老实说,笔者刚开始拿到这个图有些大意,想用DP试着解下,但是发现有些困难,随后就换了种想法,将所有可能的路线都计算一遍,比较大小,求出最小的那个(全排列的思想)。于是,使用了如下的第一种解法:

public class Main {
    private static int min = Integer.MAX_VALUE;// 预设的保存最后结果的变量
    private static Point pStart = new Point(0,0);// 用作测试的起点
    public static void main(String[] args) {
        Point[] points = new Point[4];
        points[0] = new Point(3,1);
        points[1] = new Point(2,2);
        points[2] = new Point(5,3);
        points[3] = new Point(1,4);
        DFSSolver(points,pStart,0,0);
        System.out.println(min);
    }

    /**
     * 全排列的方式将所有路径都尝试了一编
     * 循环遍历每个起点,然后从选择的起点开始进行深度优先遍历,遍历完记录sum值如果比min小就替换了
     * 采用形参的方式 维护了我们逻辑栈的变量:start、sum、count
     * @param points 所有可选起点集
     * @param start 此次选择的起点
     * @param sum 到此时,走过的路长
     * @param count 用来记录此次深度遍历是否结束
     * @return
     */
    public static void DFSSolver(Point[] points, Point start, int sum, int count) {
        for (int i = 0; i < points.length; i++) {// 决定以哪个为起点
            if(! points[i].passed){ // 如果此点访问过则继续
                points[i].passed = true; // 没有则修改为访问过
                count++;// 记录在此次选择了起点的后,已经遍历到哪个点了
                sum+=start.showDistance(points[i]);// 将此次起点到这个点的距离算上
                if(count==points.length){// 这个if才是决定最短的那条路线的长度
                    sum+=points[i].showDistance(pStart);// 将这个点到最初的起点的距离算上
                    if(sum<min){
                        min = sum;
                    }
                    System.out.println("i="+i+"; sum="+sum+"; min="+min);
                }
                DFSSolver(points, points[i],sum,count);// 递归调用,继续寻找下一个未访问过的点,如果都访问过了,那么就执行回退,回退到上一个点寻找未访问过的点
                points[i].passed = false;// 回退一格
                sum-=start.showDistance(points[i]);// 回退计算路径长度
                count --;// 回退计算访问过的点数
            }
        }
    }

	/**
     * 表示图中的点集
     */
    static class Point {
        int x;// 表示点的X轴的值
        int y;// 表示点的Y轴的值
        boolean passed = false;

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

		/**
         * 显示此点与指定点的距离
         * @param anotherPoint
         * @return
         */
        public int showDistance(Point anotherPoint) {
            return Math.abs(x - anotherPoint.x) + Math.abs(y - anotherPoint.y);
        }
    }
}

结果如图:

全排列结果

    交完卷后,粗略地浏览了下各路大神的解题思路,发现了一个哥们的想法很有意思,但是略微有些不明白的地方

    解题思路转自:传送门

    简单概括下:求出包括所有点的最小正方型。

    但是这样的话,如果内部点有出现重复路径的,就没办法判断出来了好像...,笔者按照这样的思路试了下发现答案好像不太对:

Code:

/**
     * 表示图中的点集
     */
    static class Point{
        int px;
        int py;
        boolean isVisited = false;
        public Point(int xValue,int yValue){
            px = xValue;
            py = yValue;
        }
    }

    public static void main(String[] args){
        int x = Integer.MIN_VALUE;
        int y = Integer.MIN_VALUE;
        int xStart = 0;
        int yStart = 0;
        Point[] points = new Point[]{new Point(3,1),new Point(2,2),new Point(5,3),new Point(1,4)};
        for(Point p : points){
            x = p.px>x?p.px:x;
            y = p.py>y?p.py:y;
        }
        System.out.println((x-xStart+y-yStart)<<1);
    }

结果好像不太对

嗯,就先记录到这吧!希望能有dalao指教下小弟,如果有更好的办法!毕竟全排列的解法属于挺暴力的解法的!(逃..

转载于:https://my.oschina.net/u/3744313/blog/1922802

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值