【问题标题】:Man move from source to destination with constraints人在有限制的情况下从源头移动到目的地
【发布时间】:2017-10-23 00:46:24
【问题描述】:

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

[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. 最后但同样重要的是,人只能上下左右移动。没有对角线移动。

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

【问题讨论】:

  • “机器人”和“人”是一回事吗?第二种情况下mn是什么;它们是两个节点的节点成本吗?
  • @Codor,我应该清除它。感谢您指出。是的,人和机器人是一回事。 'm' 和 'n' 是两个节点的节点成本。
  • @maraca,感谢您的来信。 S 和 D 的成本为“1”。另外,我在问题中增加了一个约束。请查看并提出建议。
  • 是什么阻止您使用像 Dijakstra 这样的标准最短路径算法?所有边成本都是已知的,都是正的,并且您有稀疏图。

标签: algorithm data-structures


【解决方案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 * dValue = 22 + 4 + 2 + 10 * 2 = 48

注意:该实现使用了 x 和 y 的行和列,因此它们被交换了,这并不重要,只要保持一致即可。

【讨论】:

  • 哇!虽然我不明白它背后的逻辑,但我还是会说“谢谢你写出来”。如果你能解释你做了什么,那就更好了。实际上,我期待“图表”方面的一些东西。
  • @HemantBhargava 添加了更多解释,维基百科的文章很不错,动画也很好upload.wikimedia.org/wikipedia/commons/5/5d/…(之前链接错了)。
  • 感谢您的反对。你可以解释吗?它给出了正确的结果,并且比其他提出的方法更有效。 @downvoter
【解决方案2】:

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

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

【讨论】:

  • 嘿@codor,非常感谢您的写作。我很欣赏第二种解决方案。也许,我也会这样做。另外,我在问题中增加了一个约束。请看一下并提出建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-25
  • 2019-10-03
相关资源
最近更新 更多