【题意】:找到最短的梯子,使小人儿可以从地面吃到图中的金币。
【算法】根据Blood Fill的思想想到的算法:
1.设梯子的长度为i=1
2.用梯子进行深度优先搜索,判断金币的可达域,
3.如不能到达地面,i++,继续2;否则return i
【编码调试BUG】
1.coin一开始就在最下层的情况,返回0;
【Java代码】来自菜鸟
import java.util.*; import java.util.regex.*; import java.text.*; import java.math.*; public class ArcadeManao { boolean[][] tag ; int row,col; public int shortestLadder(String[] level, int coinRow, int coinColumn) { int ladder=1,i,j; row = level.length; col = level[0].length(); tag = new boolean[row][col]; if(coinRow==row) return 0; while(ladder<=50){ for(i=0;i<row;i++){ for(j=0;j<col;j++){ tag[i][j]=false; } } if(dfs(level,coinRow-1,coinColumn-1,ladder)==true) break; ladder++; } if(ladder==51) ladder=0; return ladder; } public boolean dfs(String[] level,int coinRow,int coinColumn,int ladder){ //right if(moveR(level,coinRow,coinColumn,ladder)==true){ return true; } //down if(moveD(level,coinRow,coinColumn,ladder)==true){ return true; } //left if(moveL(level,coinRow,coinColumn,ladder)==true){ return true; } //up if(moveU(level,coinRow,coinColumn,ladder)==true){ return true; } return false; } public boolean moveR(String[] level,int coinRow,int coinColumn,int ladder){ if(coinColumn>=col-1) return false; if(level[coinRow].charAt(coinColumn+1)=='X'&&tag[coinRow][coinColumn+1]==false){ tag[coinRow][coinColumn+1]=true; return dfs(level,coinRow,coinColumn+1,ladder); } return false; } public boolean moveL(String[] level,int coinRow,int coinColumn,int ladder){ if(coinColumn<=0) return false; if(level[coinRow].charAt(coinColumn-1)=='X'&&tag[coinRow][coinColumn-1]==false){ tag[coinRow][coinColumn-1]=true; return dfs(level,coinRow,coinColumn-1,ladder); } return false; } public boolean moveU(String[] level,int coinRow,int coinColumn,int ladder){ int i=1; //find a 'X' while(i<=ladder&&(coinRow-i)>=0){ if(level[coinRow-i].charAt(coinColumn)=='X'&&tag[coinRow-i][coinColumn]==false){ //tag tag[coinRow-i][coinColumn]=true; return dfs(level,coinRow-i,coinColumn,ladder); } i++; } return false; } public boolean moveD(String[] level,int coinRow,int coinColumn,int ladder){ int i=1; //find a 'X' while(i<=ladder&&(i+coinRow)<row){ if(level[coinRow+i].charAt(coinColumn)=='X'&&tag[coinRow+i][coinColumn]==false){ //tag tag[coinRow+i][coinColumn]=true; //check if success if(coinRow+i==row-1) return true; return dfs(level,coinRow+i,coinColumn,ladder); } i++; } return false; } } //Powered by KawigiEdit 2.1.4 (beta) modified by pivanof!
【Java代码】来自大神
/** * Built using CHelper plug-in * Actual solution is at the top * @author Egor Kulikov (egor@egork.net) */ public class ArcadeManao { public int shortestLadder(String[] level, int coinRow, int coinColumn) { int rowCount = level.length; int columnCount = level[0].length(); char[][] map = new char[rowCount][]; for (int i = 0; i < rowCount; i++) map[i] = level[i].toCharArray(); IndependentSetSystem setSystem = new RecursiveIndependentSetSystem(rowCount * columnCount); for (int i = 0; i < rowCount; i++) { for (int j = 1; j < columnCount; j++) { if (map[i][j] == 'X' && map[i][j - 1] == 'X') setSystem.join(i * columnCount + j, i * columnCount + j - 1); } } coinRow--; coinColumn--; for (int i = 1; i <= rowCount; i++) { if (setSystem.get((rowCount - 1) * columnCount) == setSystem.get(coinRow * columnCount + coinColumn)) return i - 1; for (int j = i; j < rowCount; j++) { for (int k = 0; k < columnCount; k++) { if (map[j][k] == 'X' && map[j - i][k] == 'X') setSystem.join(j * columnCount + k, (j - i) * columnCount + k); } } } throw new RuntimeException(); } } interface IndependentSetSystem { public boolean join(int first, int second); public int get(int index); public static interface Listener { public void joined(int joinedRoot, int root); } } class RecursiveIndependentSetSystem implements IndependentSetSystem { private final int[] color; private int setCount; private Listener listener; public RecursiveIndependentSetSystem(int size) { color = new int[size]; for (int i = 0; i < size; i++) color[i] = i; setCount = size; } public RecursiveIndependentSetSystem(RecursiveIndependentSetSystem other) { color = other.color.clone(); setCount = other.setCount; } public boolean join(int first, int second) { first = get(first); second = get(second); if (first == second) return false; setCount--; color[second] = first; if (listener != null) listener.joined(second, first); return true; } public int get(int index) { if (color[index] == index) return index; return color[index] = get(color[index]); } }
【C++代码】来自大神
#include <algorithm> #include <string> #include <vector> #include <queue> #include <iostream> #include <cmath> #include <sstream> #include <map> #include <set> #include <functional> using namespace std; #define pb push_back #define INF 1000000000 #define L(s) (int)((s).size()) #define FOR(i,a,b) for (int _n(b), i(a); i <= _n; i++) #define rep(i,n) FOR(i,1,(n)) #define rept(i,n) FOR(i,0,(n)-1) #define C(a) memset((a),0,sizeof(a)) #define ll long long #define mp make_pair #define pii pair<int,int> #define x first #define y second bool used[52][52]; inline bool check(vector<string> mas, int ei, int ej, int lad) { --ei; --ej; queue<pii> q; C(used); int n = L(mas); int m = L(mas[0]); used[n - 1][m - 1] = 1; q.push(mp(n - 1, m - 1)); while (!q.empty()) { int ci = q.front().x, cj = q.front().y; q.pop(); if (cj + 1 < m && mas[ci][cj + 1] == 'X' && !used[ci][cj + 1]) { used[ci][cj + 1] = 1; q.push(mp(ci, cj + 1)); } if (cj - 1 >= 0 && mas[ci][cj - 1] == 'X' && !used[ci][cj - 1]) { used[ci][cj - 1] = 1; q.push(mp(ci, cj - 1)); } FOR(di, -lad, lad) { if (ci + di < 0 || ci + di >= n) continue; if (used[ci + di][cj]) continue; if (mas[ci + di][cj] != 'X') continue; used[ci + di][cj] = 1; q.push(mp(ci + di, cj)); } } return used[ei][ej]; } class ArcadeManao { public: int shortestLadder( vector <string> level, int coinRow, int coinColumn ) { rept(ladder, 51) { if (check(level, coinRow, coinColumn, ladder)) return ladder; } return -1; } }; // Powered by FileEdit // Powered by moj 4.17 [modified TZTester] // Powered by CodeProcessor
【分析】
【算法】Graph Theory, Simple Search, Iteration
【对比】
1.表示看不懂大神在干什么。Java大神的算法很奇怪。C++大神的算法貌似和我同源,但是好难读懂,各种宏定义。
2.菜鸟的代码可读性还可以,但是递归的实现方式捉急,如果采用堆栈的方式会更好。或者采用BFS的队列来实现也可以啊。
3.学习Java大神的这三行代码,可以很轻松地将字符串数组转换成一个字符矩阵。
char[][] map = new char[rowCount][]; for (int i = 0; i < rowCount; i++) map[i] = level[i].toCharArray();
【总结】
1.见识了Blood Fill
2.根据ladder的长度,采用Blood Fill的思想来求可达域,这个算法还是挺优雅的。