阿里線上程式設計測試題--派送貨物,求最短路徑
阿新 • • 發佈:2019-02-06
阿里線上程式設計測試題–派送貨物,求最短路徑
題目
如下圖,某物流派送員p,需要給 a、b、c、d. 4個快遞點派送包裹,請問派送員需要選擇什麼樣的路線,才能完成最短路程的派送。假設如圖派送員的起點座標(0,0),派送路線只能沿著圖中的方格邊行駛,每個小格都是正方形,且邊長為1,如p到d的距離就是4。隨機輸入n個派送點座標,求輸出最短派送路線值(從起點開始完成n個點派送並回到起始點的距離)。
輸入示例:
4
2,2
2,8
4,4
7,2
輸出:
30
思考過程
我首先想到的是把所有的路徑都嘗試一次,並求出每條路徑的總路程,從中選取最短的一條。核心思想就是全排列。後來想到了用回溯法解決:選擇所有送貨點中的任意一點作為第一個送貨點,然後繼續往下搜尋下一個點,直到將所有點都走過一遍,到達最後一個點時求出總路程並返回。這裡使用了遞迴,最難的地方在於回溯時要回到什麼地方,為了解決這個問題,需要引入一個表示送貨點狀態的boolean陣列,回溯之後靠這個陣列進入別的未嘗試過的路徑。
程式碼如下
//路徑中的點
static class Point{
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getDistance(Point point) {
return Math.abs(this.x - point.x) + Math.abs(this.y - point.y);
}
}
public static void main(String[] args) {
int pointNum = 0;
Scanner sc = new Scanner(System.in);
pointNum = Integer.parseInt(sc.nextLine().trim());
Point[] points = new Point[pointNum];
//設(0,0)點為起點
start = new Point(0, 0);
//輸入送貨點座標x,y
for(int i = 0; i < pointNum; i++) {
String[] locations = sc.nextLine().trim().split("," );
points[i] = new Point(Integer.parseInt(locations[0]), Integer.parseInt(locations[1]));
}
sc.close();
System.out.println(getMinDistance(pointNum, points));
}
private static Point start;
//將minDistance的初始值設為無窮大,即沒找到最短路徑
private static int minDistance = Integer.MAX_VALUE;
/**
* @param pointNum:送貨點數量
* @param points:送貨點陣列
*/
public static int getMinDistance(int pointNum, Point[] points) {
int distance = 0;
//flag陣列用於標記該點是否已搜尋
boolean[] flag = new boolean[pointNum];
//分別將各個點作為第一個送貨點進行搜尋
for(int i = 0; i < pointNum; i++) {
distance += start.getDistance(points[i]);
DFSSearch(i, distance, flag, points, 1, pointNum);
}
return minDistance;
}
/**
*
* @param index:當前點
* @param distance:當前路徑長度
* @param flag:是否在該路徑的標誌,true為在,false為不在
* @param points:送貨點陣列
* @param level:搜尋深度,即搜尋到第幾個點
* @param allLevel:搜尋總深度,一共要搜尋幾個點
*/
private static void DFSSearch(int index, int distance, boolean[] flag, Point[] points, int level, int allLevel) {
if(level == allLevel) {
//搜尋到最後一個點時計算其與起點的距離,求得整個送貨過程的總路程
distance += start.getDistance(points[index]);
if(distance < minDistance) {
minDistance = distance;
}
return;
}
//將當前路徑標記為true,表示在當前路徑上
flag[index] = true;
for(int i = 0; i < points.length; i++) {
//前往下一條沒有被搜尋過得路徑
//條件為該路徑的flag為false
if(!flag[i]) {
//先計算當前這個點與即將前往的下一個點之間的距離
distance += points[index].getDistance(points[i]);
//繼續往下搜尋
//此時搜尋深度+1
DFSSearch(i, distance, flag, points, level+1, allLevel);
}
}
//當前點已搜尋完,退出當前路徑,返回上一個點
//將當前路徑的flag設為false
flag[index] = false;
}