SRM DIV2 576 ArcadeManao

【题意】:找到最短的梯子,使小人儿可以从地面吃到图中的金币。

【算法】根据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的思想来求可达域,这个算法还是挺优雅的。

    

原文地址:https://www.cnblogs.com/wang3/p/3216896.html