[英]Algorithm for finding the shortest path in a two-dimensional array
请帮我实现以下算法。 我是初学者,这个问题让我失望。
该算法应该找到从左上角到右下角的最短路径。 右下方的元素始终为 0。数组始终为正方形(例如 3x3)。
您只能沿着阵列向下或向右移动。 当前的 position 和 int 元素,即所谓的跳跃力(例如,如果我们在点 [0] [0] 开始,对应的元素是 2,那么我们可以将 2 向下移动(D2)-> [2] [0] 或右侧 2 (R2) -> [0] [2])。 如果跳跃的力量让我们离开场地(例如,一个 3x3 阵列,我们踩到了 5 号单元格,那么无论如何我们都从两个方向飞离场地),我们需要重新开始并寻找另一种方式。
一种算法应该计算路径/一个人必须跳跃/行走的顺序,以便以尽可能少的跳跃次数到达终点。
算法如何工作的示例(因此,路径将是 [D1, R2, D1] - 向下移动一次,向右移动两次,向下移动一次)
我尝试了不同的方法,现在我在用输入 int[][] 制作隐式图形后正在努力使用 DFS,而我得到的答案不是最短路径。 我还听说动态编程可能会有所帮助,但不知道如何实现。
我几乎没有测试的代码包括:
public class Main {
int indexError = 0;
int shortestPathLen = Integer.MAX_VALUE;
List<String> shortestPath = new ArrayList<>();
List<List<String>> allPaths;
List<String> solution = new ArrayList<>();
public List<List<String>> findAllPaths(int[][] map, int D, int R) {
int currentPosition = map[D][R]; //D - down, R - right
if (currentPosition == 0) {
allPaths.add(solution);
return allPaths;
}
if (D + currentPosition <= indexError) {
solution.add("D" + currentPosition);
findAllPaths(map, D+currentPosition, R);
}
if (R + currentPosition <= indexError) {
solution.add("R" + currentPosition);
findAllPaths(map, D, R+currentPosition);
}
solution = new ArrayList<>();
return allPaths;
}
public List<String> findPath(int[][] map) {
indexError = map[0].length - 1;
shortestPathLen = Integer.MAX_VALUE;
allPaths = new ArrayList<>();
List<List<String>> l = findAllPaths(map, 0, 0);
for (List<String> path : l) {
if (path.size() < shortestPathLen) {
shortestPathLen = path.size();
shortestPath = path;
}
}
return shortestPath;
}
public static void main(String[] args) {
Main main = new Main();
// int len = 3;
// int[] array = {1, 2, 2,
// 2, 10, 1,
// 3, 2, 0}; // from example
int len = 9;
int[] array =
{1, 10, 20, 1, 2, 2, 1, 2, 2,
1, 10, 1, 10, 2, 2, 1, 2, 2,
1, 10, 1, 1, 20, 2, 1, 2, 2,
2, 1, 10, 1, 1, 20, 1, 2, 2,
1, 2, 2, 10, 1, 1, 10, 2, 2,
2, 1, 1, 1, 10, 1, 1, 20, 2,
1, 2, 2, 1, 2, 10, 1, 1, 20,
1, 1, 1, 1, 2, 2, 10, 1, 1,
1, 2, 1, 1, 2, 2, 1, 1, 0};
int[][] map = new int[len][len];
int k = 0;
for (int i = 0; i < len; i++) {
for (int j = 0; j < len; j++) {
map[i][j] = array[k];
k++;
}
}
List result = main.findPath(map);
System.out.println("\n" + result + ", " + result.size() + " jumps");
// = must be [D1, D1, D1, D2, R2, D1, R2, D2, R2, R1, R1], 11 jumps
}}
使用此代码(A*-Search),您将不会获得最佳解决方案,但几乎不会。
//= D1, D1, D1, D2, D2, D1, R1, R2, R1, R2, R1, R1, 12 jumps
如果您可以更改distanceToGoal() - 方法以更好地估计到目标的真实距离,您将获得最佳解决方案。
public class TestClass {
private static class Position implements Comparable<Position>{
private final int[][] map;
private int x;
private int y;
List<String> path = new ArrayList<>();
/**
* Some Constructors
*/
public Position(int[][] map) {
this(map, 0, 0);
}
public Position(Position parent, Consumer<Position> consumer, String action) {
this(parent.map, parent.x, parent.y);
consumer.accept(this);
this.path.addAll(parent.path);
this.path.add(action);
}
private Position(int[][] map, int x, int y) {
this.map = map;
this.x = x;
this.y = y;
}
/**
* Returns Jumpforce of current position
*/
public int getJumpForce() {
return this.map[this.y][this.x];
}
/**
* Returns steps taken till current position
*/
public int steps() {
return CollectionUtils.size(this.path);
}
/**
* Method calculates the estimated way to the goal. In this case the mannhatten distance
*/
private int distanceToGoal() {
var height = ArrayUtils.getLength(this.map);
var width = ArrayUtils.getLength(this.map);
return (height - (y+1)) + (width - (x+1));
}
/**
* Sum of steps taken and the estimated distance till the goal
*/
private int totalCosts() {
return this.steps() + this.distanceToGoal();
}
public boolean isGoal() {
return this.map[this.y][this.x] == 0;
}
/**
* Returns a list of all successor states
*/
public List<Position> successors() {
var s = new ArrayList<Position>();
if (ArrayUtils.getLength(this.map) > (this.y + this.getJumpForce())) {
s.add(new Position(this,
p -> p.y += this.getJumpForce(),
String.format("D%d", this.getJumpForce())));
}
if (ArrayUtils.getLength(map[y]) > (x + this.getJumpForce())) {
s.add(new Position(this,
p -> p.x += this.getJumpForce(),
String.format("R%d", this.getJumpForce())));
}
return s;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Position position = (Position) o;
return new EqualsBuilder()
.append(x, position.x)
.append(y, position.y)
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder(17, 37)
.append(x)
.append(y)
.toHashCode();
}
@Override
public int compareTo(Position o) {
return Comparator.comparing(Position::totalCosts).compare(this, o);
}
@Override
public String toString() {
return String.join(", ", path);
}
}
public static Position findShortestPath(int[][] map) {
var visited = new HashSet<Position>();
var fringe = new PriorityQueue<Position>(){{
add(new Position(map));
}};
// As long as there is a position to check
while (CollectionUtils.isNotEmpty(fringe)) {
// Get that position
var position = fringe.poll();
//If we didn't look already at this position
if (!visited.contains(position)) {
// Check if its the goal
if (position.isGoal()) {
return position;
} else {
//Mark position as visited
visited.add(position);
//Add all successors to be checked
fringe.addAll(position.successors());
}
}
}
// If no solution is found
return null;
}
public static void main(String[] args) {
// int len = 3;
// int[] array = {1, 2, 2,
// 2, 10, 1,
// 3, 2, 0}; // from example
int[][] map = { {1, 10, 20, 1, 2, 2, 1, 2, 2},
{1, 10, 1, 10, 2, 2, 1, 2, 2},
{1, 10, 1, 1, 20, 2, 1, 2, 2},
{2, 1, 10, 1, 1, 20, 1, 2, 2},
{1, 2, 2, 10, 1, 1, 10, 2, 2},
{2, 1, 1, 1, 10, 1, 1, 20, 2},
{1, 2, 2, 1, 2, 10, 1, 1, 20},
{1, 1, 1, 1, 2, 2, 10, 1, 1},
{1, 2, 1, 1, 2, 2, 1, 1, 0} };
Position position = findShortestPath(map);
if (Objects.nonNull(position)) {
System.out.printf("%s, %d jumps%n", position, position.steps());
} else {
System.out.println("No solution found");
}
// = must be [D1, D1, D1, D2, R2, D1, R2, D2, R2, R1, R1], 11 jumps
}
}
或者使用深度优先搜索方法。
public List<List<String>> findAllPaths(int[][] map, int D, int R) {
System.out.printf("findPath(map, %d, %d) called %n", D, R);
// Get the limits of the map
int mapSize_Y = map.length;
int mapSize_X = map[0].length;
// If given coordinates are not in the map
// Since the moves are restircted to down and right, no need to check lower border
if (R >= mapSize_X || D >= mapSize_Y) {
System.out.printf("Point at (%d, %d) not in the map%n", D, R);
return null;
}
int jumpStrength = map[D][R]; //D - down, R - right
if (jumpStrength == 0) {
System.out.printf("Found goal at (%d, %d)%n", D, R);
return Collections.emptyList();
}
// Move forward and call the function recursively
// Spoken - get all subpaths that are possible from this point on
var subPathsDown = findAllPaths(map, D + jumpStrength, R);
System.out.printf("subpaths after findPath(map, %d, %d) returned -> %s%n", D + jumpStrength, R, subPathsDown);
var subPathsRight = findAllPaths(map, D, R + jumpStrength);
System.out.printf("subpaths after findPath(map, %d, %d) returned -> %s%n", D, R + jumpStrength, subPathsRight);
// Add the move that produced the subpaths to the result
var subPaths = new HashMap<String, List<List<String>>>() {{
if (Objects.nonNull(subPathsDown)) {
put("D" + jumpStrength, subPathsDown);
}
if (Objects.nonNull(subPathsRight)) {
put("R" + jumpStrength, subPathsRight);
}
}};
// If no further path is found return
if (MapUtils.isEmpty(subPaths)) {
System.out.printf("No valid Subpaths at Point (%d, %d) %n", D, R);
return null;
}
// Change key-value structure to a list with the key as first entry
// and the values of the map value afterwards
List<List<String>> result = subPaths.entrySet()
.stream()
.flatMap(e -> {
if (CollectionUtils.isEmpty(e.getValue())) {
return Stream.of(new ArrayList<String>() {{
add(e.getKey());
}});
}
return e.getValue()
.stream()
.map(sp -> new ArrayList<String>() {{
add(e.getKey());
addAll(sp);
}});
})
.collect(Collectors.toList());
return result;
}
此外,您可以删除Main -Class 的所有属性,如果您将findPath -Method更改为:
public List<String> findPath(int[][] map) {
int shortestPathLen = Integer.MAX_VALUE;
List<String> shortestPath = new ArrayList<>();
List<List<String>> l = findAllPaths(map, 0, 0);
for (List<String> path : l) {
if (path.size() < shortestPathLen) {
shortestPathLen = path.size();
shortestPath = path;
}
}
return shortestPath;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.