釣魚問題-DFS全排列+模擬
阿新 • • 發佈:2018-12-24
題目:釣魚崗位有N(5<=N<>=60),釣魚人數P(1<=P<=20),總共有3個入口,3個入口位置在不同的釣魚崗,從入口到達入口對應的釣魚崗距離為1,從該位置往兩邊走,能夠到達下一個釣魚崗,距離也為1。現在每個入口有一定的人排隊,求出所有入口處的人全部到達釣魚崗最小的距離。每個釣魚崗只能有一個人。
2 4
3 2
10 3
20
3 10
6 2
13 2
11
10 6
3 3
6 2
10
10 3
1 3
5 3
10
4 5
6 2
10 2
case: 10import java.io.FileInputStream; import java.io.FileNotFoundException; import java.util.Scanner; //先左還是先右對結果是有影響的,所以兩次情況都要考慮到 public class Test32_1216_diaoyu { static int roomNum;// 港口的數量 static int[] fishRoom;// 釣魚港口陣列 static int[] theDoor = new int[3];// 入口的位置 static int[] people;// 入口對應的人數 static int step1 = 0;// 優先放右邊的步數 static int step2 = 0;// 優先放左邊的步數 static int minStep = 1000000;// 最小的步數 public static void main(String[] args) throws FileNotFoundException { long s = System.currentTimeMillis(); Scanner in = new Scanner(new FileInputStream("D:\\test\\Test1216_diaoyu.txt")); while (in.hasNext()) { roomNum = in.nextInt(); fishRoom = new int[roomNum]; people = new int[roomNum]; for (int i = 0; i < 3; i++) { int ind = in.nextInt() - 1; theDoor[i] = ind; people[ind] = in.nextInt(); } // 初始化 minStep = 1000000; // 呼叫全排列DFS DFS(theDoor, 0, theDoor.length - 1); System.out.println(minStep); } // 程式執行時間 long e = System.currentTimeMillis(); System.out.println(e - s + "MS"); } // 全排列入口的開放順序 public static void DFS(int[] theDoor, int start, int end) { // 迭代結束條件 if (start == end) {// 出口--插入怎樣往釣魚港口放人的函式 // 初始化港口陣列(0代表沒人,1代表已經有人) fishRoom = new int[roomNum]; step1 = 0;// 初始化步數 // 按照入口開放順序放人(優先往右邊放) goFishing1(theDoor); fishRoom = new int[roomNum]; step2 = 0;// 初始化步數 // 優先往右邊放 goFishing2(theDoor); // 找出step1和step2中較小的一個 int min = step1 > step2 ? step2 : step1; // 更新最小步數 if (min < minStep) { minStep = min; } } else { // 入口開放順序的全排列迭代體 for (int i = start; i <= end; i++) { int temp = theDoor[start]; theDoor[start] = theDoor[i]; theDoor[i] = temp; DFS(theDoor, start + 1, end); temp = theDoor[start]; theDoor[start] = theDoor[i]; theDoor[i] = temp; } } } /* * ---以下為模擬入口放人各種情況。debug了好長時間,仍然認為不是最簡單的辦法 */ // 按照入口開放順序放人(優先往右邊放) public static void goFishing1(int[] theDoor) { for (int i = 0; i < 3; i++) {// 遍歷三個入口 int doorNum = theDoor[i];// 該入口的位置 int perNum = people[doorNum];// 該入口的人數 letGo1(doorNum, perNum, 1, doorNum); } } // 按照入口開放順序放人(優先往左邊放) public static void goFishing2(int[] theDoor) { for (int i = 0; i < 3; i++) {// 遍歷三個入口 int doorNum = theDoor[i];// 該入口的位置 int perNum = people[doorNum];// 該入口的人數 letGo2(doorNum, perNum, 1, doorNum); } } // 將該入口的人放去港口(DFS先右再左) // temp為判斷往右還是往左放的標誌位;stLen為入口的位置,用來計算步數用 public static void letGo1(int doorNum, int perNum, int temp, int stLen) { if (perNum != 0) { if (doorNum >= 0 && doorNum < roomNum) { if (fishRoom[doorNum] == 0) { fishRoom[doorNum] = 1; int index = (doorNum - stLen) > 0 ? (doorNum - stLen + 1) : (stLen - doorNum + 1);// 每放一個人的步數 step1 = step1 + index;// 累計步數 perNum--;// 等待人數減少 // doorNum <roomNum- 1防止陣列越界 if (temp % 2 == 1 && doorNum < roomNum) { letGo1(doorNum + temp, perNum, temp + 1, stLen); } else { letGo1(doorNum - temp, perNum, temp + 1, stLen); } } else {// 如果最近的釣魚口已經有人在,接著往下找 if (temp % 2 == 1 && doorNum < roomNum) { letGo1(doorNum + temp, perNum, temp + 1, stLen); } else { letGo1(doorNum - temp, perNum, temp + 1, stLen); } } } else { if (doorNum < 0) {// 如果超出陣列範圍,分情況考慮 letGo1(doorNum + temp, perNum, temp + 1, stLen); } else { letGo1(doorNum - temp, perNum, temp + 1, stLen); } } } } // 將該入口的人放去港口(DFS先左再右) // temp為判斷往右還是往左放的標誌位;stLen為入口的位置,用來計算步數用 public static void letGo2(int doorNum, int perNum, int temp, int stLen) { if (perNum != 0) { if (doorNum >= 0 && doorNum < roomNum) {// 如果在陣列範圍內 if (fishRoom[doorNum] == 0) { fishRoom[doorNum] = 1; int index = (doorNum - stLen) > 0 ? (doorNum - stLen + 1) : (stLen - doorNum + 1); step2 = step2 + index; perNum--; if (temp % 2 == 0 && doorNum < roomNum - 1) { letGo2(doorNum + temp, perNum, temp + 1, stLen); } else { letGo2(doorNum - temp, perNum, temp + 1, stLen); } } else {// 如果最近的釣魚口已經有人在,接著往下找 if (temp % 2 == 0 && doorNum < roomNum - 1) { letGo2(doorNum + temp, perNum, temp + 1, stLen); } else { letGo2(doorNum - temp, perNum, temp + 1, stLen); } } } else {// 如果超出陣列範圍,分情況考慮 if (doorNum < 0) { letGo2(doorNum + temp, perNum, temp + 1, stLen); } else { letGo2(doorNum - temp, perNum, temp + 1, stLen); } } } } }
2 4
3 2
10 3
20
3 10
6 2
13 2
11
10 6
3 3
6 2
10
10 3
1 3
5 3
10
4 5
6 2
10 2