java bfs统计路径数_java-使用BFS查找网格上对象的可能路径数

虽然BFS / DFS通常用于查找起点和终点之间的连接,但实际上并非如此. BFS / DFS是“图形遍历算法”,这是一种花哨的说法,可以说它们发现了从起点可到达的每个点. DFS(深度优先搜索)更易于实现,因此我们将根据您的需要使用它(注意:当您需要查找到起点的任何距离时,都将使用BFS;仅在需要时才使用DFS.去每一点).

我不知道您的数据的确切结构,但是我假设您的地图是一个整数数组,并定义了一些基本功能(为简单起见,我将第一个单元格设置为2):

Map.java

import java.awt.*;

public class Map {

public final int width;

public final int height;

private final Cell[][] cells;

private final Move[] moves;

private Point startPoint;

public Map(int[][] mapData) {

this.width = mapData[0].length;

this.height = mapData.length;

cells = new Cell[height][width];

// define valid movements

moves = new Move[]{

new Move(1,0),new Move(-1,new Move(0,1),-1)

};

generateCells(mapData);

}

public Point getStartPoint() {

return startPoint;

}

public void setStartPoint(Point p) {

if (!isValidLocation(p)) throw new IllegalArgumentException("Invalid point");

startPoint.setLocation(p);

}

public Cell getStartCell() {

return getCellAtPoint(getStartPoint());

}

public Cell getCellAtPoint(Point p) {

if (!isValidLocation(p)) throw new IllegalArgumentException("Invalid point");

return cells[p.y][p.x];

}

private void generateCells(int[][] mapData) {

boolean foundStart = false;

for (int i = 0; i < mapData.length; i++) {

for (int j = 0; j < mapData[i].length; j++) {

/*

0 = empty space

1 = wall

2 = starting point

*/

if (mapData[i][j] == 2) {

if (foundStart) throw new IllegalArgumentException("Cannot have more than one start position");

foundStart = true;

startPoint = new Point(j,i);

} else if (mapData[i][j] != 0 && mapData[i][j] != 1) {

throw new IllegalArgumentException("Map input data must contain only 0,1,2");

}

cells[i][j] = new Cell(j,i,mapData[i][j] == 1);

}

}

if (!foundStart) throw new IllegalArgumentException("No start point in map data");

// Add all cells adjacencies based on up,down,left,right movement

generateAdj();

}

private void generateAdj() {

for (int i = 0; i < cells.length; i++) {

for (int j = 0; j < cells[i].length; j++) {

for (Move move : moves) {

Point p2 = new Point(j + move.getX(),i + move.getY());

if (isValidLocation(p2)) {

cells[i][j].addAdjCell(cells[p2.y][p2.x]);

}

}

}

}

}

private boolean isValidLocation(Point p) {

if (p == null) throw new IllegalArgumentException("Point cannot be null");

return (p.x >= 0 && p.y >= 0) && (p.y < cells.length && p.x < cells[p.y].length);

}

private class Move {

private int x;

private int y;

public Move(int x,int y) {

this.x = x;

this.y = y;

}

public int getX() {

return x;

}

public int getY() {

return y;

}

}

}

单元格

import java.util.LinkedList;

public class Cell {

public final int x;

public final int y;

public final boolean isWall;

private final LinkedList adjCells;

public Cell(int x,int y,boolean isWall) {

if (x < 0 || y < 0) throw new IllegalArgumentException("x,y must be greater than 0");

this.x = x;

this.y = y;

this.isWall = isWall;

adjCells = new LinkedList<>();

}

public void addAdjCell(Cell c) {

if (c == null) throw new IllegalArgumentException("Cell cannot be null");

adjCells.add(c);

}

public LinkedList getAdjCells() {

return adjCells;

}

}

现在编写我们的DFS函数. DFS通过以下步骤递归地触摸每个可达单元一次:

>将当前单元格标记为已访问

>遍历每个相邻的单元格

>如果尚未访问该单元格,请DFS该单元格,并将与该单元格相邻的单元格数量添加到当前计数中

>返回与当前单元格1相邻的单元格数

您可以看到此here的可视化.使用我们已经编写的所有帮助程序功能,这非常简单:

MapHelper.java

class MapHelper {

public static int countReachableCells(Map map) {

if (map == null) throw new IllegalArgumentException("Arguments cannot be null");

boolean[][] visited = new boolean[map.height][map.width];

// subtract one to exclude starting point

return dfs(map.getStartCell(),visited) - 1;

}

private static int dfs(Cell currentCell,boolean[][] visited) {

visited[currentCell.y][currentCell.x] = true;

int touchedCells = 0;

for (Cell adjCell : currentCell.getAdjCells()) {

if (!adjCell.isWall && !visited[adjCell.y][adjCell.x]) {

touchedCells += dfs(adjCell,visited);

}

}

return ++touchedCells;

}

}

就是这样!让我知道您是否需要有关代码的任何说明.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值