人有限制从源移动到目的地

时间:2017-05-23 07:31:58

标签: algorithm data-structures

考虑这个笛卡尔图,其中每个指数代表一个权重。

[3,2,1,4,2

1,3,3,2,2

S ,3,4,1, D

3,1,2,4,3

4,2,3,1,4]

一名男子站在源头'S',他必须以最低成本到达目的地'D'。约束是:

  1. 如果男子从一个指数移动到另一个指数,其中两个指数共享相同的成本,那么移动人的成本为'1'。

  2. 如果男子从一个指数移动到另一个指数,其中两个指数的成本不同,那么移动人的成本是abs(n-m)* 10 + 1.

  3. 最后但并非最不重要的是,男人只能向上,向下,向左和向下移动。对。没有对角线移动。

  4. 哪种数据结构&算法最适合这个问题。我曾想过将这个问题表示为一个图表并使用其中一种贪婪的方法,但在我的脑海中无法达到清洁的解决方案。

2 个答案:

答案 0 :(得分:1)

虽然没有明确说明,但在问题公式中似乎只有正节点权重,这意味着最短路径不会重复节点。由于成本不仅取决于节点,因此Bellman-Ford算法或Dijkstra算法不适合。

话虽如此,显然可以通过使用depth-first search递归地找到路径,其中可能不会访问当前在堆栈中出现的节点。每次到达目的地时,可以针对先前找到的最佳路径评估当前路径(在每次到达目的地时包含在堆栈中)以及可以在辅助变量中维护的相关成本。终止时,将存储成本最低的路径。

答案 1 :(得分:1)

我会用A *来解决问题。距离可以通过dx + dy + 10 * dValue +行进距离来估算(路径不可能比那个短,见底部示例)。一旦找到完成的目标节点,A *的想法就是始终扩展具有最低估计距离的节点。如果估计从不过度估计距离,则此方法有效。这是JS(fiddle)中的一个实现:

function solve(matrix, sRow, sCol, eRow, eCol) {
    if (sRow == eRow && sCol == eCol)
        return 0;
    let n = matrix.length, m = matrix[0].length;
    let d = [], dirs = [[-1, 0], [0, 1], [1, 0], [0, -1]];
    for (let i = 0; i < n; i++) {
        d.push([]);
        for (let j = 0; j < m; j++)
            d[i].push(1000000000);
    }
    let list = [[sRow, sCol, 0]];
    d[sRow][sCol] = 0;
    for (;;) {
        let pos = list.pop();
        for (let i = 0; i < dirs.length; i++) {
            let r = pos[0] + dirs[i][0], c = pos[1] + dirs[i][1];
            if (r >= 0 && r < n && c >= 0 && c < m) {
                let v = d[pos[0]][pos[1]] + 1 + 10 * Math.abs(matrix[pos[0]][pos[1]] - matrix[r][c]);
                if (r == eRow && c == eCol)
                    return v;
                if (v < d[r][c]) {
                    d[r][c] = v;
                    list.push([r, c, v + Math.abs(r - eRow) + Math.abs(c - eCol) + 10 * Math.abs(matrix[r][c] - matrix[eRow][eCol])]);
                }
            }
        }
        list.sort(function(a, b) {
            if (a[2] > b[2])
                return -1;
            if (a[2] < b[2])
                return 1;
            return 0;
        });
    }
}

该示例的答案是46,只有8个节点正在扩展!

估算示例,从(0,0)到D:

  • 从S到(0,0)的距离是22
  • dx = abs(0 - 4)= 4
  • dy = abs(0 - 2)= 2
  • dValue = abs(3 - 1)= 2
  • 估计=距离+ dx + dy + 10 * d值= 22 + 4 + 2 + 10 * 2 = 48

注意:实现使用x和y的行和列,因此它们是交换的,它并不重要,只需要保持一致。