之前寫給同學的程式碼,關於搜尋的一些題型
阿新 • • 發佈:2018-12-03
其中有用到一些自己寫的類(棧,佇列)改成JDK自帶的即可。。。
1 import java.util.Scanner; 2 3 class BestMaze{ //這是我總結作業中,關於最佳圖的問題,的類 4 int[] d1; 5 int[] d2; 6 int[][] map; 7 int m, n, count, minlen; 8 int l = 0; //l是指牆數(當然是有牆的情況才用) 9 Queue<Point> q; 10 Stack<Point> s;11 Point[] wall; 12 public BestMaze(){ 13 this(0,0,null,null); 14 } 15 public BestMaze(int m, int n, int[] d1, int[] d2){ 16 this.m = m; 17 this.n = n; 18 this.d1 = d1; //搜尋中縱座標(也就是x)的偏移值陣列 19 this.d2 = d2; //搜尋中橫座標(也就是y)的偏移值陣列20 this.count = -1; 21 map = new int[m+1][n+1]; 22 wall = new Point[(m+1)*(n+1)]; //純英文意思就是,牆(就是這個位置走不了的意思) 23 } 24 public boolean meetWall(Point p){ //判斷是否撞牆 25 if(!(p.x>=0 && p.x<m && p.y>=0 && p.y<n)) 26 returnfalse; 27 for(int j = 0; j < l; j++) 28 if(wall[j].x == p.x && wall[j].y == p.y) 29 return false; 30 return true; 31 } 32 public void Bestlen(Point start, Point end){ //佇列廣搜,蒽 33 map = new int[m+1][n+1]; 34 q = new LinkedQueue<Point>(); 35 map[start.x][start.y] = 1; //先把起始點標記了,不要跑路的時候又踩了這裡 36 start.step = 0; 37 q.add(start); 38 39 while(!q.isEmpty()){ 40 Point front = q.poll(); //隊頭搞出來 41 42 if(front.x == end.x && front.y == end.y){ //判斷是否到達終點,到就停 43 minlen = front.step; 44 break; 45 } 46 47 for(int i = 0; i < d1.length; i++){ 48 //移動的下一個點,定義為前一個點的偏移值後的位置 49 Point move = new Point(front.x+d1[i], front.y+d2[i], front.step+1); 50 51 boolean flag = meetWall(move); //判斷牆,也可以結合某點是否走過使用 52 53 if(flag && map[move.x][move.y]==0){ 54 q.add(move); 55 map[move.x][move.y] = move.step; //記錄能到這個點的最快步數 56 } 57 } 58 } 59 map[start.x][start.y] = 0; //起始點當然還是要變回0的嘛 60 } 61 public void BestCount(Point start, Point end){ //其實是深搜,蒽 62 //最快到達的次數有多少種的方法,類似上面的地方就不備註了 63 map = new int[m+1][n+1]; 64 s = new LinkedStack<Point>(); //注意這裡用棧! 65 s.push(start); 66 start.step = 0; 67 68 while(!s.isEmpty()){ 69 Point front = s.pop(); 70 71 if(front.x == end.x && front.y == end.y) 72 count++; 73 74 for(int i = 0; i < d1.length; i++){ 75 Point move = new Point(front.x+d1[i], front.y+d2[i], front.step+1); 76 77 boolean flag = meetWall(move); 78 79 if(flag && (map[move.x][move.y]==map[front.x][front.y]+1)) 80 s.push(move); 81 //這裡是不需要標記步數的,只要能走就入棧 82 } 83 } 84 } 85 public int BestArea(){ //這個也是深搜,想看效果可以把測試輸出的地方取消備註,呼叫就可以了 86 int max = 0, t; 87 s = new LinkedStack<Point>(); 88 89 for(int i = 0; i < m; i++) 90 for(int j = 0; j < n; j++){ 91 if(map[i][j] == 1){ //這裡是"1"是未走的路 92 t = 1; 93 s.push(new Point(i, j)); 94 map[i][j] = 0; //"0"是牆 95 96 while(!s.isEmpty()){ 97 Point f = s.pop(); 98 for(int k = 0; k < d1.length; k++){ 99 int dx = f.x + d1[k]; 100 int dy = f.y + d2[k]; 101 102 if(dx>=0 && dx<m && dy>=0 && dy<n && map[dx][dy] == 1){ 103 s.push(new Point(dx, dy)); 104 map[dx][dy] = 0; //走過就變成牆,也可以染色(某一塊區域同一個數字) 105 t++; 106 } 107 } 108 } 109 // outMap(); //這是測試輸出的地方 110 // System.out.println(t); 111 if(max < t) //這是找面積最大的 112 max = t; 113 } 114 } 115 116 return max; 117 } 118 //求最短路徑,返回點集 119 public Point[] Bestload(Point start, Point end){ 120 // Bestlen(start, new Point(-1, -1)); //廣搜全圖 121 Bestlen(start, end); //廣搜終點 122 // outMap(); 廣搜後再深搜 123 124 s = new LinkedStack<Point>(); 125 s.push(start); 126 while(!s.isEmpty()){ 127 Point front = s.peek(); 128 boolean t = true; 129 130 if(front.x == end.x && front.y == end.y){ 131 break; 132 } 133 for(int i = 0; i < d1.length; i++){ 134 Point move = new Point(front.x+d1[i], front.y+d2[i]); 135 136 boolean flag = meetWall(move); //判斷是否撞牆 137 138 if(flag && (map[move.x][move.y]==map[front.x][front.y]+1)){ 139 wall[l++] = move; //走過的地方設定為牆 140 s.push(move); 141 // System.out.println("入棧:"+move + ",,"+map[move.x][move.y]); 142 t = false; 143 break; //確定一次走路只走一點 144 } 145 } 146 if(t){ //若此點四周都是牆,就丟了 147 // System.out.println("出--" + s.peek()); 148 s.pop(); 149 } 150 } 151 int len = map[end.x][end.y]+1; //結果集的長度肯定是深搜後到達終點的最小步數 152 Point[] result = new Point[len]; 153 154 // StringBuffer sb = new StringBuffer(); //除錯,檢視結果 155 while(!s.isEmpty()) 156 { 157 result[--len] = s.peek(); //倒序裝回點集 158 // sb.insert(0, s.peek()); //除錯,檢視結果 159 s.pop(); 160 } 161 162 // System.out.println(sb.toString()); //除錯,檢視結果 163 return result; 164 } 165 public void outMap(){ //檢視圖的情況 166 for(int i = 0; i < m; i++){ 167 for(int j = 0; j < n; j++) 168 System.out.print(map[i][j] + " "); 169 System.out.println(); 170 } 171 } 172 173 public static void migonglujing(String[] args) { //最短迷宮路徑的main方法 174 Scanner sc = new Scanner(System.in); 175 int id = 1; 176 int[] d1 = {0, 1, 1, 1, 0, -1, -1, -1}; 177 int[] d2 = {1, 1, 0, -1, -1, -1, 0, 1}; 178 while(sc.hasNext()){ 179 int m = sc.nextInt(); 180 int n = sc.nextInt(); 181 // if(m == 0 && n == 0) break; 182 BestMaze maze = new BestMaze(m, n, d1, d2); 183 int l = 0; 184 for(int i = 0; i < m; i++) 185 for(int j = 0; j < n; j++) 186 if(sc.nextInt() == 1) //輸入為1,是牆 187 maze.wall[l++] = new Point(i, j); 188 maze.l = l; //確定牆的數量 189 Point[] result = maze.Bestload(new Point(0, 0), new Point(m-1, n-1)); 190 for(int i = 0; i < result.length-1; i++) 191 System.out.print(result[i] + "->"); 192 System.out.print(result[result.length-1]); 193 194 } 195 System.gc();sc.close(); 196 } 197 198 public static void Qishijuhui(String[] args) { //這是騎士聚會問題的main方法 199 Scanner sc = new Scanner(System.in); 200 int id = 1; 201 int[] d1 = {-2, -1, 1, 2, 2, 1, -1, -2}; 202 int[] d2 = {1, 2, 2, 1, -1, -2, -2, -1}; 203 while(sc.hasNext()){ 204 int n = sc.nextInt(); 205 int m = sc.nextInt(); 206 // if(m == 0 && n == 0) break; 207 BestMaze[] maze = new BestMaze[m]; //求出每個騎 208 for(int i = 0; i < m; i++){ 209 maze[i] = new BestMaze(n, n, d1, d2); 210 maze[i].Bestlen(new Point(sc.nextInt(), sc.nextInt()), new Point(-1, -1)); 211 } 212 // // 檢視廣搜後的結果,你可以取消備註看看。。。 213 // int[][] count = new int[n][n]; 214 // 215 // for(int i = 0; i < m; i++){ 216 // for(int j = 0; j < n; j++){ 217 // for(int k = 0; k < n; k++){ 218 // count[j][k] += maze[i].map[j][k]; 219 // System.out.print(maze[i].map[j][k] + "\t"); 220 // } 221 // System.out.println(); 222 // } 223 // if(i == m-1){ 224 // System.out.println("------------總步數--------------"); 225 // for(int j = 0; j < n; j++){ 226 // for(int k = 0; k < n; k++) 227 // System.out.print(count[j][k] + "\t"); 228 // System.out.println(); 229 // } 230 // } 231 // System.out.println("-------------------------------"); 232 // } 233 // // 下面開始找最佳位置(所有騎士到這裡的總天數最小,天數相等情況下要最晚到的騎士步數最小的) 234 235 int[][] countday = new int[n][n]; 236 int minday = 99999; 237 int lastday = 0; 238 Point bestposition = null; 239 240 for (int i = 0; i < n; i++) 241 for (int j = 0; j < n; j++) { 242 int day = 0; 243 int last = 0; //這個位置上,最晚到達的騎士的天數 244 245 for (int k = 0; k < m; k++) { //求所有騎士到這位置的總天數 246 day += maze[k].map[i][j]; 247 if (maze[k].map[i][j] > last) //記住最晚的那個 248 last = maze[k].map[i][j]; 249 } 250 if (minday > day) { //要天數最小的位置 251 minday = day; 252 bestposition = new Point(i, j); 253 lastday = last; 254 } 255 //天數相等情況下,要最晚到達的騎士的步數最小的位置 256 else if (minday == day && last < lastday) { 257 bestposition = new Point(i, j); 258 lastday = last; 259 } 260 countday[i][j] = day; 261 } 262 System.out.println("最佳聚會位置: " + bestposition); 263 System.out.println("最晚到達聚會的騎士走了" + lastday +"天"); 264 System.out.println("總步數為: " + countday[bestposition.x][bestposition.y]); 265 } 266 267 System.gc();sc.close(); 268 } 269 }