1. 程式人生 > >阿里內推題——物流派送員送快遞最短路徑問題

阿里內推題——物流派送員送快遞最短路徑問題

題目:

如下圖,某物流派送員p,需要給 a、b、c、d. 4個快遞點派送包裹,請問派送員需要選擇什麼樣的路線,才能完成最短路程的派送。假設如圖派送員的起點座標(0,0),派送路線只能沿著圖中的方格邊行駛,每個小格都是正方形,且邊長為1,如p到d的距離就是4。隨機輸入n個派送點座標,求輸出最短派送路線值(從起點開始完成n個點派送並回到起始點的距離)。
這裡寫圖片描述

輸入示例:
4
2,2
2,8
4,4
7,2
輸出:
30

分析:這道題我想到的辦法是將所有送貨點組合的路徑都計算一次長度,取其中的最小即可,而如何獲取所有的路徑組合呢?其實也就是將所有的送貨點做一次全排列。最後記錄下所有的長度取其最短即可【這裡需要注意的是,我們取長度的時候需要計算回到原地的路徑】。

下面貼一個取全排列的演算法(因為此題的核心是基於全排列演算法)

import java.util.Arrays;

public class AllRange {
    // 需要被全排列的陣列
    private static String[] arr = "a,b,c,d".split(",");

    public static void main(String[] args) {
        rangeAll(arr, 0);
    }

    /**
     * 全排列指定陣列
     *
     * @param arr
     *            需要被全排列的陣列
     * @param n
     *            記錄遞迴的層數(從0開始)
     */
    public static void rangeAll(String[] arr, int n) {
        if (n == arr.length) {
            // 列印陣列
            System.out.println(Arrays.toString(arr));
            return;
        }
        for (int i = n; i < arr.length; i++) {
            swap(arr, n, i);
            rangeAll(arr, n + 1);
            swap(arr, n, i);
        }
    }

    /**
     * 交換陣列中指定的兩個數
     *
     * @param arr
     * @param i
     * @param j
     */
    public static void swap(String[] arr, int i, int j) {
        if (i == j) {
            return;
        }
        String temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47

針對此題的程式碼為:

import java.io.InputStream;
import java.util.Scanner;

/**
 * 計算快遞員在各個點送快遞最短路徑問題:<br>
 * 輸入引數例子: <br/>
 * 4<br/>
 * 2,2 <br/>
 * 2,8 <br/>
 * 4,4<br/>
 * 7,2 <br/>
 * 輸出應為:30
 *
 * @author 藍亭書序
 *
 */
public class Main {
    // 起始點
    static final Point START = new Point(0, 0);
    // 記錄最短路徑(預設是“無限大”表示不可達)
    static int minPath = Integer.MAX_VALUE;

    public static void main(String[] args) {
        // 建立輸入解析器
        InputParser parser = new InputParser(System.in);
        parser.parse();// 獲取輸入,開始轉換
        System.out.println(rangeAll(parser.getPoints(), 0));
    }

    /**
     * 用全排列解決此問題
     *
     * @param points
     * @param n
     */
    public static int rangeAll(Point[] points, int n) {
        if (n == points.length) {
            // 計算這次排列的路徑長度
            int sum = points[0].getLength(START);
            for (int i = 1; i < points.length; i++) {
                sum += points[i - 1].getLength(points[i]);
            }
            // 【千萬不要忘了加上回到原點的路徑】
            sum += points[points.length - 1].getLength(START);
            // 記錄最短長度【其實這裡也可以記錄下路徑詳情(也就是這次全排列的順序)】
            minPath = Math.min(minPath, sum);
            return minPath;
        }
        // 全排列演算法部分
        for (int i = n; i < points.length; i++) {
            swap(points, n, i);
            rangeAll(points, n + 1);
            swap(points, n, i);
        }
        return minPath;
    }

    /**
     * 交換陣列的i,j兩個值
     *
     * @param points
     * @param i
     * @param j
     */
    public static void swap(Point[] points, int i, int j) {
        if (i == j) {
            return;
        }
        Point temp = points[i];
        points[i] = points[j];
        points[j] = temp;
    }

}

/**
 * 輸入解析類
 *
 * @author 藍亭書序
 *
 */
class InputParser {

    private Scanner scanner;// 輸入掃描器
    private Point[] points;// 點集
    private int num;// 總共有幾個點

    public InputParser(InputStream in) {
        scanner = new Scanner(in);
    }
    public Point[] getPoints() {
        return points;
    }
    public int getNum() {
        return num;
    }
    /**
     * 解析輸入,格式例如:<br/>
     * 3<br/>
     * 2,2<br/>
     * 2,8<br/>
     * 6,6<br/>
     */
    public void parse() {
        // 獲取有幾個點
        num = Integer.parseInt(scanner.nextLine().trim());
        points = new Point[num];// 構建點陣列
        // 分別獲取各個點的座標
        for (int i = 0; i < num; i++) {
            String[] locations = scanner.nextLine().trim().split(",");
            points[i] = new Point(Integer.parseInt(locations[0]), Integer.parseInt(locations[1]));
        }
    }
}

/**
 * 送貨點類
 *
 * @author 藍亭書序
 *
 */
class Point {
    int px;
    int py;

    public Point(int px, int py) {
        this.px = px;
        this.py = py;
    }

    /**
     * 獲取與指定點之間的距離
     *
     * @param p
     * @return
     */
    public int getLength(Point p) {
        return Math.abs(px - p.px) + Math.abs(py - p.py);
    }
}

---------------------
作者:LanTingShuXu
來源:CSDN
原文:https://blog.csdn.net/LanTingShuXu/article/details/81277306
版權宣告:本文為博主原創文章,轉載請附上博文連結!