我目前被困在一个项目上。 我的目标是使用Dijkstra的算法。
据我所知,我从点(0,0)开始,我查看起点旁边的两个节点,然后先移动到最小的节点,然后查看周围的节点。我的迷宫是随机的,但为了让它易于启动,我可以说以下是我的迷宫。
我将从(0,0)开始,并希望以(9,9)结束数字是危险等级,我们的目标是最安全的路径不是最短的。
我需要了解如何设置它。 我知道我需要一个列表或路径来保持我的位置以及我想要的位置。但我不知道如何在java中做到这一点。
import java.awt.Point;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class solver {
/**
* @param args
*/
public static int[][]maze;
public static int[][]openlist;
public static int[][]closed;
public static int[][]copy;
public static int danger;
public static int size=100;
static int Max=9;
static int Min=0;
public static List path = new ArrayList();
public static void main(String[] args) {
// TODO Auto-generated method stub
maze = new int[size][size];
openlist = new int[size][size];
closed = new int[size][size];
copy = new int[size][size];
filler(maze);
copy=dijstkra();
printer(maze);
//printer(copy);
EDSfAO(maze,0,0);
printer(openlist);
printer(copy);
}
private static Boolean notwall(int i, int j){
if((i>maze.length-1)||(j>maze.length-1)||(i<0)||(j<0))
{return false;}
return true;}
private static int[][] dijstkra(){
for(int i=0;i<maze.length;i++){
for(int j=0;j<maze.length;j++){
copy[i][j]=100000000;
}}
copy[0][0]=0;
return copy;
}
private static void EDSfAO(int[][] maze,int i,int j){
int min=100000000;
int holdx = 0;
int holdy = 0;
openlist[i][j]=1;
danger=copy[i][j];
if(i==maze.length-1&&j==maze.length-1){
printer(copy);
for(holdx=0;holdx<path.size();holdx++){
System.out.print(path.get(holdx));
}
}
else{
if(notwall(i+1,j)&&openlist[i+1][j]!=1){
copy[i+1][j]=danger+maze[i+1][j];
} if(notwall(i,j+1)&&openlist[i][j+1]!=1){
copy[i][j+1]=danger+maze[i][j+1];
} if(notwall(i,j-1)&&openlist[i][j-1]!=1){
copy[i][j-1]=danger+maze[i][j-1];
} if(notwall(i-1,j)&&openlist[i-1][j]!=1){
copy[i-1][j]=danger+maze[i-1][j];
}
for(int x=0;x<maze.length;x++){
for(int y=0;y<maze.length;y++){
if(openlist[x][y]!=1){
if(min>copy[x][y]){
min=copy[x][y];
holdx=x;
holdy=y;
}
}
}}
moveToPosition(holdx,holdy);
}
}
private static void moveToPosition(int x, int y) {
openlist[x][y]=1;
path.add("("+x+","+y+")");
openlist[x][y]=1;
EDSfAO(maze,x,y);
}
private static void printer(int[][] maze) {
// TODO Auto-generated method stub
for(int i=0;i<maze.length;i++){
for(int j=0;j<maze.length;j++){
System.out.print("["+maze[i][j]+"]");
}
System.out.println();
}
}
public static void filler(int[][] maze){
for(int i=0;i<maze.length;i++){
for(int j=0;j<maze.length;j++){
//If i=0 AND j=0 then maze[0][0]= 0(start) OR i= maze.length-1 AND j= maze.length-1 then maze[maze.length][maze.length]=0
if((i==0 && j==0) || (i==maze.length-1 && j==maze.length-1)){
maze[i][j]=0;
}else{
maze[i][j]=Min + (int)(Math.random() * ((Max - Min) + 1));
}
}
}
}
}
迷宫连接没有墙壁所有的盒子都是房间。 我一直试图在这方面努力,我真的可以使用推动。 我看过很多关于dijstkra算法的视频,我现在真的迷失了。
我添加了一个数组,我保持其中的危险,首先是节点100000000,但起始节点(0,0)为0.
有人可以帮助我完成接下来的步骤我理解它的功课但是我已经没时间了,而且确实需要一些指示。
更新:
好的,所以我有点工作。它会打印它所采用的路径,但是如果它找到了更好的路径,它可以帮助我解决这个问题。
如果我做100X100元素也会有人告诉我原因吗? 这是真正的“编程任务”的最后一个。正如您所料,这将涉及图表(有一个扭曲);但当然,也会涉及一些解决问题的方法。 指令
想象一下“地下城游戏”,所有的房间都布置在一个完美的网格中,在一个方形的环境中。每个房间都有一个具有一定程度危险的生物,范围从0(无害)到9(避免是谨慎的)。目标是从头到尾找到穿过地下城的路径,这样可以最大限度地减少危险。
每个房间,除非在边界,只存在于上,下,左,右方向(没有对角线)。入口位于左上角(0,0),出口位于右下角(n-1,n-1)。
从开始到结束,以房间坐标路径的形式列出所有必须经过的“房间”。
例如:
(0,0) (1,0) (2,0) (2,1) (2,2) (2,3) (3,3) (4,3) (4,4)
总危险= 11 输入
输入文件由100行100位数字组成,0-9。 (是的,10,000是很多房间,但幸运的是,我们勇敢的旅行者在去年的节日礼物交换中没有便携式计算机和收集所有场合的电子数据集的情况下永远不会离开家;它可能是重新获得的。 )*
*对于此作业,您必须生成自己的测试数据。这就是为什么我不参加这些派对...... 输出
程序应将输出写入文件(采用上述格式,包括“总危险”输出)。 感谢。
UPDATE2:我发现我的编码错误
if(min>copy[x][y]){
min=copy[x][y];
holdx=x;
holdy=y;
}
这将使它测试给定点的每条路径,我的最短路径大于另一条路径,我该如何解决这个问题?
我错过了什么? 更新我感谢非常小的帮助。
答案 0 :(得分:11)
一旦您了解了如何使用Dijkstra算法,您就可以使用ArrayList
包含指示您之前位置的数字对:
List<Point> path = new ArrayList<Point>();
然后,您可以撰写一个Point
课程,其中只包含两个int
原语,x
和y
。
所以当你移动时,你可以使用:
private void moveToPosition(int x, int y) {
path.add(new Point(x, y));
// Move yourself to this point
...
}
至于学习如何使用算法,我认为这有点是你的功课,我们不想破坏你的乐趣!
关于算法的维基百科文章非常有用,但我觉得你的课堂笔记也会有所帮助。
答案 1 :(得分:4)
我刚刚查看了Dijkstra's Algorithm上的维基百科文章。
- 为每个节点分配一个暂定距离值:为我们的初始节点设置为零,为所有其他节点设置为无穷大。
- 标记未访问的所有节点。将初始节点设置为当前节点。创建一组称为未访问集的未访问节点 由除初始节点之外的所有节点组成。
- 对于当前节点,考虑所有未访问的邻居并计算其暂定距离。例如,如果是当前的 节点A标记为距离为6,边缘连接它 邻居B的长度为2,那么到B(通过A)的距离就是 6 + 2 = 8。如果此距离小于先前记录的距离, 然后覆盖那个距离。即使是邻居也是如此 经检查,此时未标记为已访问,并且仍然存在 未经审查的集合。
- 当我们考虑当前节点的所有邻居时,将当前节点标记为已访问并将其从中删除 未经审查的集合。永远不会再次检查受访节点;它的 现在记录的距离是最终的,最小的。
- 如果未访问的集合为空,则停止。算法已经完成。
- 将标记有最小暂定距离的未访问节点设置为下一个“当前节点”,然后返回步骤3.
醇>
首先要天真地接近它。哎呀,把它当作“程序员的阅读理解”。在这种情况下,技巧是将二维数组映射到一组图形节点。每个节点都需要“暂定距离值”。好的,你的节点是由它们的i,j值定义的。制作一些东西,这样你就可以获得/设置一个给定i和j的tentative_distance_value。
您需要标记是否访问过某个节点。同样的想法。
您需要一个“当前节点”。同样的想法,但更简单。
我知道我需要一个列表或路径来保持。我是,我想要 看。但我不知道如何在java中做到这一点。
从技术上讲,不需要维护运行算法的路径。如果不这样做,你必须弄清楚如何从算法的结果中构造它,但它肯定是可能的。
答案 2 :(得分:4)
您可以将解决方案基于Cormen,Leiserson,Rivest和Stein,第2版“算法导论”中的算法。在第24章中,他们分析了“单源最短路径”算法,在24.3中你有Dijkstra。
我将在这里使用伪代码。您可以使用Java中的另一个数据结构替换下面的最小优先级队列。它不会很快但它会起作用,这可能是一个令人满意的第一次尝试。如果需要,我还有一个最小优先级队列的Java实现。
假设你的代码中有一个2D数组所代表的迷宫:int [M] [N]迷宫。第一个索引是行索引,第二个索引是列索引,从零开始。因此,对于行,从0到M-1,对于列从0到N-1。值迷宫[row] [column]表示与(行,列)房间相关的危险。我们需要一个方便的表示来获得迷宫中两个房间之间的重量,并知道哪个房间与特定房间相邻。
我们的想法是将数组展平并将每一行并排放置:row1,row2,...,rowM。然后我们可以给每个房间索引一个。为了能够使用这个想法,我们需要在不同类型的坐标之间进行转换:(行,列) - &gt;我和我 - &gt; (行,列)。
convert_to_index(row, column) ::= row * N + column
convert_to_pair(i) ::= (i div N, i modulo N)
说SIZE是M * N,即迷宫中的房间总数。
现在我们可以创建一个邻接矩阵来表示具有危险值的迷宫:int [SIZE] [SIZE] adjacency_matrix,第一个索引是FROM,第二个索引是TO。在单元格中,我们发现从一个房间到另一个房间的成本或重量。请注意,给定一个特定的房间,只有几个房间与该房间相邻。迷宫中的其他房间无法从那个房间到达。按照惯例,我们将使用最大的整数来表示并使用常量INFINITY。其他值代表危险,范围从0到9.矩阵将是稀疏的,并且有一些技术可以优化它。
当我们在(r,c)有一个房间时,它旁边的房间是什么?我们希望在我们的算法中直接使用索引向量。如果我们不考虑迷宫边界,我们有:(r-1,c-1),(r-1,c),(r-1,c + 1),(r,c-1) ,(r,c + 1),(r + 1,c-1),(r + 1,c)和(r + 1,c + 1)。然后我们可以将convert_to_index应用于它们中的每一个,检查它们是否在0..SIZE-1范围内并用它初始化矩阵。因此,例如,从(r,c)到(r-1,c-1)具有迷宫的成本或危险[r-1,c-1]并且从(r-1,c-1)变为(r,c)有迷宫费[r,c]。但是从(r,c)到另一个遥远的房间的成本是10,它是无法到达的,反之亦然。
adjacent_rooms(r, c) ::=
Given the vector [(r-1, c-1), (r-1, c), (r-1, c+1), (r, c-1), (r, c+1), (r+1, c-1), (r+1, c), (r+1,c+1)]
Filter it by deleting pairs whose row is not in 0..M-1 or whose column is not in 0..N-1
Then apply the function convert_to_index to each resulting pair (map operation)
Return the result
for i in 0..SIZE-1 loop
for j in 0..SIZE-1 loop
adjacency_matrix[i, j] := -1
end loop
end loop
for i in 0..SIZE-1 loop
(current_r, current_c) := convert_to_pair(i)
adjacent_room_indexes := adjacent_rooms(current_r, current_c)
for j in 0..SIZE-1 loop
if adjacency_matrix[i, j] == -1 then
(r, c) := convert_to_pair(j)
if i == j then adjacency_matrix[i, j] := 0
elsif j in adjacent_room_indexes then adjacency_matrix[i, j] := maze[r, c]; adjacency_matrix[j, i] := maze[current_r, current_c]
else adjacency_matrix[i, j] := INFINITY
end if
end loop
end loop
接下来,我们需要最短路径估计的向量估计(Cfr。书页585)和前辈向量(Cfr。book page 584)。
for i in 0..SIZE-1 loop
predecessors[i] := NONE
estimates[i] := INFINITY
end loop
从开始到开始费用为0.
estimates[0] := 0
初始化属于MST(最小生成树)的顶点集
mst := empty set
初始化最小优先级队列q
for i in 0..SIZE-1 loop
q.add(i, estimates[i])
end loop
until q.empty? loop
u, u_d = q.delete_min
mst.add(u)
(current_r, current_c) := convert_to_pair(i)
adjacent_room_indexes := adjacent_rooms(current_r, current_c)
for i in 0..adjacent_room_indexes.length-1 loop
v := adjacent_room_indexes[i]
cost = adjacency_matrix[u, v]
if cost < q[v]
predecessors[v] = u
estimates[v] = c
q[v] = c
end
end loop
end loop
工作完成了。我们的路径位于predecessors
,费用为estimates
。
这可能是矫枉过正的,A *可能会更好。但我想使用Dijkstra是你作业的要求。如果您想探索A *,建议您查看A* Pathfinding for Beginners和Amit’s A* Pages。
答案 3 :(得分:2)
我继续执行ccoakley提到的算法。在下面找到部分代码,以帮助您朝着正确的方向前进:
import java.util.HashSet;
import java.util.Set;
// 1. Assign to every node a tentative distance value: set it to zero for our initial node and to infinity for all other nodes.
// 2. Mark all nodes unvisited. Set the initial node as current. Create a set of the unvisited nodes called the unvisited set consisting of all the nodes except the initial node.
// 3. For the current node, consider all of its unvisited neighbors and calculate their tentative distances. For example, if the current node A is marked with a distance of 6, and the edge connecting it with a neighbor B has length 2, then the distance to B (through A) will be 6+2=8. If this distance is less than the previously recorded distance, then overwrite that distance. Even though a neighbor has been examined, it is not marked as visited at this time, and it remains in the unvisited set.
// 4. When we are done considering all of the neighbors of the current node, mark the current node as visited and remove it from the unvisited set. A visited node will never be checked again; its distance recorded now is final and minimal.
// 5. If the unvisited set is empty, then stop. The algorithm has finished.
// 6. Set the unvisited node marked with the smallest tentative distance as the next "current node" and go back to step 3.
public class Dijkstra {
class Node {
String name;
Integer distance = Integer.MAX_VALUE;
boolean visited;
Set<Edge> edges = new HashSet<Edge>();
Node(String name) {
this.name = name;
}
Edge connect(Node destination, int length) {
Edge edge = new Edge();
edge.length = length;
edge.from = this;
edge.to = destination;
edges.add(edge);
destination.edges.add(edge);
return edge;
}
@Override
public String toString() {
return name;
}
}
class Edge {
int length;
Node from;
Node to;
Node getNeighbor(Node origin) {
if (from == origin) {
return to;
}
else if (to == origin) {
return from;
}
else {
throw new IllegalArgumentException("This edge is not connected to node " + origin);
}
}
@Override
public String toString() {
return String.format("%s-%s", from, to);
}
}
/**
* <pre>
* a - b - c
* | |
* d - e |
* |
* f - g - h
* </pre>
*
* @return
*/
private Set<Node> initialize() {
Node a = new Node("a");
Node b = new Node("b");
Node c = new Node("c");
Node d = new Node("d");
Node e = new Node("e");
Node f = new Node("f");
Node g = new Node("g");
Node h = new Node("h");
a.connect(b, 4);
a.connect(d, 8);
b.connect(c, 6);
b.connect(e, 1);
c.connect(h, 7);
d.connect(e, 2);
d.connect(f, 5);
f.connect(g, 3);
g.connect(h, 1);
a.distance = 0;
Set<Node> unvisited = new HashSet<Dijkstra.Node>();
unvisited.add(a);
unvisited.add(b);
unvisited.add(c);
unvisited.add(d);
unvisited.add(e);
unvisited.add(f);
unvisited.add(g);
unvisited.add(h);
return unvisited;
}
private Set<Node> solve(Set<Node> unvisited) {
Set<Node> visited = new HashSet<Node>();
while (!unvisited.isEmpty()) {
System.out.println(String.format("Unvisited nodes:%s", unvisited.size()));
print(unvisited);
Node current = findNodeWithSmallestDistance(unvisited);
System.out.println(String.format("Current node:%s", current));
updateNeighbors(current);
current.visited = true;
unvisited.remove(current);
visited.add(current);
}
return visited;
}
private void updateNeighbors(Node current) {
for (Edge edge : current.edges) {
Node neighbor = edge.getNeighbor(current);
if (!neighbor.visited) {
int tentativeNeighborDistance = current.distance + edge.length;
if (tentativeNeighborDistance < neighbor.distance) {
neighbor.distance = tentativeNeighborDistance;
System.out.println(String.format("Neighbor:%s distance:%s", neighbor, neighbor.distance));
}
else {
System.out.println(String.format("Neighbor:%s no shorter path found", neighbor));
}
}
else {
System.out.println(String.format("Neighbor:%s already visited", neighbor));
}
}
}
private Node findNodeWithSmallestDistance(Set<Node> nodes) {
Node smallest = null;
for (Node node : nodes) {
if (smallest == null || node.distance < smallest.distance) {
smallest = node;
}
}
return smallest;
}
private void print(Set<Node> visited) {
for (Node node : visited) {
System.out.println(String.format("Node:%s has distance:%s", node, node.distance));
}
}
public static void main(String[] args) {
Dijkstra edsger = new Dijkstra();
Set<Node> unvisited = edsger.initialize();
Set<Node> visited = edsger.solve(unvisited);
edsger.print(visited);
}
}
编辑:添加了缺失的位