Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 求矩阵中的最短路径和。Dijkstra不是这种情况下的最佳选择吗?_Algorithm_Go - Fatal编程技术网

Algorithm 求矩阵中的最短路径和。Dijkstra不是这种情况下的最佳选择吗?

Algorithm 求矩阵中的最短路径和。Dijkstra不是这种情况下的最佳选择吗?,algorithm,go,Algorithm,Go,我正在尝试解决(请看链接中的描述和示例,但这里是简短的解释) 在矩阵中,通过向左、向右、向上和向下移动,找到从左上到右下的最小路径和 在我研究了这个问题之后,我想到了一个显而易见的解决方案,就是从矩阵中创建一个图,然后用它来寻找最短路径 要从N*M矩阵构造图形,对于每个(i,j)元素,我创建一个顶点i*N+j,并将其连接到任何其他顶点(可以与上、右、下、左连接),边将是我在矩阵中连接到的元素的值。之后,我创建了另外两个顶点-1连接到顶点0和-2连接到N*M-1,这两个顶点将成为我的开始和结束顶点

我正在尝试解决(请看链接中的描述和示例,但这里是简短的解释)

在矩阵中,通过向左、向右、向上和向下移动,找到从左上到右下的最小路径和

在我研究了这个问题之后,我想到了一个显而易见的解决方案,就是从矩阵中创建一个图,然后用它来寻找最短路径

要从
N*M
矩阵构造图形,对于每个
(i,j)
元素,我创建一个顶点
i*N+j
,并将其连接到任何其他顶点(可以与上、右、下、左连接),边将是我在矩阵中连接到的元素的值。之后,我创建了另外两个顶点
-1
连接到顶点
0
-2
连接到
N*M-1
,这两个顶点将成为我的开始和结束顶点(两个连接的成本均为0)

在这之后,我在做Dijkstra以找到从
-1
-2
的最短路径成本。我的Dijkstra实现使用优先级队列,看起来是这样的:

func dijkstraCost(graph map[int]map[int]int, start, end int) int{
    if start == end{
        return 0
    }
    frontier := make(PriorityQueue, 1)
    frontier[0] = &Item{value: start, priority: 0, index: 0}
    visited := map[int]bool{}
    heap.Init(&frontier)

    for frontier.Len() > 0 {
        element := heap.Pop(&frontier).(*Item)
        vertex, cost := element.value, element.priority
        visited[vertex] = true
        neighbors := graph[vertex]
        for vertex_new, cost_new := range(neighbors){
            if !visited[vertex_new]{
                if vertex_new == end{
                    return cost + cost_new
                }
                heap.Push(&frontier, &Item{
                    value: vertex_new,
                    priority: cost + cost_new,
                })
            }
        }
    }
    return -1
}
其中,优先级队列实现是从堆容器(例如PriorityQueue)中获取的,只需稍作修改:

func (pq PriorityQueue) Less(i, j int) bool {
    return pq[i].priority > pq[j].priority // changed to <
}

这是正确的,但问题是它被认为是低效的(从数据判断)。它应该在不到4秒的时间内为
700x700
矩阵运行查找最佳解决方案的值,而我的解决方案需要10秒

我认为我在go中做错了什么,所以我用python重新实现了相同的解决方案(700x700矩阵大约需要70秒)


我的问题是:我是否使用正确的方法在矩阵中找到最佳解决方案。如果是这样,我的实现有什么问题


另外,我有完整的go和python解决方案,只是觉得即使没有它们,问题也太长了。

Dijkstra应该通过了,我只是用JAVA提交了一份报告,完成每个任务不到一秒钟

正如我所提到的,矩阵中的每个值都可能达到10^9,您的解决方案可能会遇到数字溢出问题,这会影响运行时间

我的代码:

<!-- language:java -->

static int[]X = {0,1,0,-1};
static int[]Y = {1,0,-1,0};
public static void main(String[] args) throws FileNotFoundException {
    // PrintWriter out = new PrintWriter(new FileOutputStream(new File(
    // "output.txt")));
    PrintWriter out = new PrintWriter(System.out);
    Scanner in = new Scanner();        
    int n = in.nextInt();
    long[][]map = new long[n][n];
    for(int i = 0; i < n; i++){
        for(int j = 0; j < n; j++){
            map[i][j] = in.nextLong();
        }
    }
    PriorityQueue<Pos> q= new PriorityQueue();
    long[][]dist = new long[n][n];
    for(long[]a : dist){
        Arrays.fill(a,Long.MAX_VALUE);
    }
    q.add(new Pos(0,0,map[0][0]));
    dist[0][0] = map[0][0];
    while(!q.isEmpty()){
        Pos p = q.poll();
        if(dist[p.x][p.y] == p.cost){
            for(int i = 0; i < 4; i++){
                int x = p.x + X[i];
                int y = p.y + Y[i];
                if(x >= 0 && y >= 0 && x < n && y < n && dist[x][y] > dist[p.x][p.y] + map[x][y] ){
                    dist[x][y] = dist[p.x][p.y] + map[x][y];
                    q.add(new Pos(x,y,dist[x][y]));
                }
            }
        }
    }
    out.println(dist[n - 1][n - 1]);
    out.close();
}

static class Pos implements Comparable<Pos>{
    int x, y;
    long cost;
    public Pos(int x, int y, long cost) {
        super();
        this.x = x;
        this.y = y;
        this.cost = cost;
    }
    @Override
    public int compareTo(Pos o) {
        // TODO Auto-generated method stub
        return Long.compare(cost, o.cost );
    }
}
在您的实现中,当顶点从堆中弹出时,您只能更新
已访问的
,因此,可以多次添加和处理一个顶点,因此,它将显著增加您的时间复杂性

修理

for frontier.Len() > 0 {
    element := heap.Pop(&frontier).(*Item)
    vertex, cost := element.value, element.priority
    if !visited[vertex]{
        visited[vertex] = true
        neighbors := graph[vertex]
        for vertex_new, cost_new := range(neighbors){
            if !visited[vertex_new]{
                if vertex_new == end{
                   return cost + cost_new
                }
                heap.Push(&frontier, &Item{
                   value: vertex_new,
                   priority: cost + cost_new,
                })
            }
        }   
    }

问这个不是更好吗?@Tichodroma我不确定问题出在代码上(我不是要求人们检查我的代码),可能是我使用了错误的算法。代码审查的另一个问题是,那里的人不多,很难在go there中找到有知识的人。代码看起来太过简单,无法重新查看,这会使代码审查偏离主题。关于使用哪种算法的问题不应该张贴在那里。如果你有一个可接受的启发式,A*将比Dijkstra的更快-你能想到一个在这种情况下吗?@MichaelFoukarakis啊,我忘了A*对于可接受和一致的启发式是最优的。这里的启发法接近最后一个平方(可以计算为出租车距离。谢谢你告诉我这一点。现在的问题是我做错了什么。我非常怀疑这与溢出有关(我对700x700矩阵的测试值为1到100,大约需要10秒).Ps,我看不到您的解决方案(HR正在隐藏它),但只要我知道它在1秒内通过了所有测试,这并不重要。@Salvadodali我认为您的实现中存在错误,请查看我的更新:)您完全正确。谢谢你,看到我犯了这样的错误,我很难过。你能告诉我你花了多少时间通过测试5和6吗?@Salvadodali测试5是0.86秒,测试6是0.85秒
for frontier.Len() > 0 {
    element := heap.Pop(&frontier).(*Item)
    vertex, cost := element.value, element.priority
    //You didn't check for visited vertex here!
    visited[vertex] = true
    neighbors := graph[vertex]
    for vertex_new, cost_new := range(neighbors){
        if !visited[vertex_new]{//You can add same vertex multiple times here!
            if vertex_new == end{
                return cost + cost_new
            }
            heap.Push(&frontier, &Item{
                value: vertex_new,
                priority: cost + cost_new,
            })
        }
    }
}
for frontier.Len() > 0 {
    element := heap.Pop(&frontier).(*Item)
    vertex, cost := element.value, element.priority
    if !visited[vertex]{
        visited[vertex] = true
        neighbors := graph[vertex]
        for vertex_new, cost_new := range(neighbors){
            if !visited[vertex_new]{
                if vertex_new == end{
                   return cost + cost_new
                }
                heap.Push(&frontier, &Item{
                   value: vertex_new,
                   priority: cost + cost_new,
                })
            }
        }   
    }