Algorithm 带障碍物的图算法DFS/BFS的实现

Algorithm 带障碍物的图算法DFS/BFS的实现,algorithm,graph,depth-first-search,breadth-first-search,Algorithm,Graph,Depth First Search,Breadth First Search,我想问你是否可以给我一个关于基于图算法的任务的建议-DFS或BFS。 这项任务背后有一个故事。在宇宙中,有很多行星。这些行星中的一些受到一种危险病毒的感染,这种病毒会杀死所有人。 我们的任务是找到一条从一个星球到一个有药物的星球的路径,这样就有可能治愈人类的病毒。 由于病毒的存在,找到路径是相当危险的。机组人员可能会去病毒所在的星球(他们知道病毒在哪个星球),但他们去那里是因为他们没有其他选择,因为他们必须找到药物。在被感染的星球上,机组人员被感染,并有一段时间可以生存(时间是从一个星球到另一个

我想问你是否可以给我一个关于基于图算法的任务的建议-DFS或BFS。 这项任务背后有一个故事。在宇宙中,有很多行星。这些行星中的一些受到一种危险病毒的感染,这种病毒会杀死所有人。 我们的任务是找到一条从一个星球到一个有药物的星球的路径,这样就有可能治愈人类的病毒。 由于病毒的存在,找到路径是相当危险的。机组人员可能会去病毒所在的星球(他们知道病毒在哪个星球),但他们去那里是因为他们没有其他选择,因为他们必须找到药物。在被感染的星球上,机组人员被感染,并有一段时间可以生存(时间是从一个星球到另一个星球的一种方式)。这个任务的结果应该是一条从起始行星到有药物的行星的路径。它应该适用于任何已知宇宙的地图

一个已知的有行星的宇宙的例子。起始行星为0,终止行星为13。正如你所看到的,行星1,2,4都被感染了。在这个具体的例子中,机组人员感染后还有一天可以活。因此,如果机组人员前往行星1,他们会受到感染,然后在下一个行星(4或6)死亡。如果他们去了行星2,他们会被感染,他们只有一天的生命,所以在下一个行星上死亡。。。其结果是路径0 3 10 11 12 5 13

另一个已知有行星的宇宙的例子。起始行星为0,终止行星为9。正如你所看到的,行星4,6,7都被感染了。在这个具体的例子中,机组人员感染后还有两天的生命。因此,如果机组人员前往行星4,他们会受到感染,两天后(一天=从一个行星到另一个行星的一条路)死亡。其结果是路径01 2 3 5 7 6 9或01 2 3 5 7 8 9。正如您所看到的,在某些情况下,可能会有更多的路径。任务是只找到一个,而不必是最短的。只有一条正确的路线,船员们从起点到终点。


我已经使用了迭代DFS算法,但我不知道如何实现这样一个部分:如果机组人员在一条路径上死亡,算法应该找到另一条路径。您可以从图形的图片中获得它。

您可以使用最短路径算法,如查找两个节点之间的最短路径

边权重就是您可能要访问的节点的权重。在这种情况下,所有指向非病毒节点的边的权重都将为
1
。而到病毒节点的边的权重为
节点数+1
。访问任何一个病毒行星都比访问所有其他行星成本更高。这样,病毒行星只有在没有其他选择的情况下才会被选择

它还处理了你必须访问多个病毒行星的情况,通过选择病毒行星数量最少的路径,而这在这种情况下并不重要。虽然如果你想列出所有同样有效的解决方案,你可以考虑任何额外的病毒行星重量为1,如果路径已经包括一个病毒行星。然后,如果它与最佳解决方案具有相同的权重,则只需将其显示为另一个有效解决方案

至于生存时间,我们称之为
T
,只需检查当前路径即可。如果搜索中的当前节点不是结束节点,并且自第一个病毒行星穿过后它一直是
T
行星。然后将该路径视为无效而拒绝


《生存时间》的另一种处理方法是使用数组权重,
[路径权重,病毒年龄]
。这意味着,给定相同的路径权重,它将扩展病毒龄最低的路径。病毒年龄仅为暴露于病毒后的
#天

如果您不在乎它是否是最短路径,您可以使用DFS并进行一些调整,以合并死亡时间功能。和javascript代码:

function findPath(path, infectedNodes, nodesBeforeDeath, initialNode, targetNode, adjacentTable) {
  const lastNode = path.visitedNodes[path.visitedNodes.length - 1];
  
  if (lastNode === targetNode) {
    return path;
  }

  if (path.nodesLeftBeforeDeath !== null && path.nodesLeftBeforeDeath !== undefined && path.nodesLeftBeforeDeath == 0) {
    return;
  }
 
  const adjacentNodes = adjacentTable[lastNode];
  
  for (const node of adjacentNodes) {
    if (path.visitedNodes.indexOf(node) > -1) {
        continue;
    }
    
    const newPath = {
        visitedNodes: [...path.visitedNodes, node]
    };
    
    if (path.nodesLeftBeforeDeath !== null && path.nodesLeftBeforeDeath !== undefined) {
        newPath.nodesLeftBeforeDeath = path.nodesLeftBeforeDeath - 1;
    }
    else if (infectedNodes.indexOf(node) > - 1) {
        newPath.nodesLeftBeforeDeath = nodesBeforeDeath;
    }
    
    const nodeResult = findPath(newPath, infectedNodes, nodesBeforeDeath, initialNode, targetNode, adjacentTable);
    
    if (nodeResult) {
        return nodeResult;
    }
  }
}

const firstExampleResult = findPath({
  visitedNodes: [0]
  },
  [1, 2, 4],
  1,
  0,
  13,
  [[1,2,3,4],
  [0,4,6],
  [0, 7, 8],
  [0, 9, 10],
  [0, 1, 11, 12],
  [6, 12, 13],
  [1, 5, 7],
  [2,6,14],
  [2,9,14],
  [3,8],
  [3, 11],
  [4,10,12],
  [4,5,11],
  [5],
  [7,8]]
);

console.log(firstExampleResult.visitedNodes);

const secondExampleResult = findPath({
  visitedNodes: [0]
  },
  [4, 6, 7],
  2,
  0,
  9,
  [
  [1],
  [0,2],
  [1,3],
  [2,4,5],
  [3,7],
  [3,7],
  [7,9],
  [4,5,6,8],
  [7,9],
  [6,8]
  ]
);
console.log(secondExampleResult.visitedNodes);

您可以通过修改BFS来解决此问题。在进行BFS时,保持感染天数作为状态的一部分。然后,在遍历时,如果我们访问的受感染天数更好(即更少),则接受对以前访问过的节点的遍历

这也是最短路径,因为BFS将在非加权图中生成最短路径

下面是应用于第二个示例的Python快速草图:

from collections import deque

def bfs(graph, virus_nodes, start, target, survive_days):
    survive_days = min(survive_days, len(graph)) 
    visited = {start : 0}
    queue = deque([(start, 0, (start,))]) # node, days infected, path

    while queue:
        node, days_infected, path = queue.popleft()
        is_infected = days_infected > 0 or node in virus_nodes

        nxt_days_infected = days_infected + 1 if is_infected else 0
        if nxt_days_infected > survive_days:
            continue

        for nxt in graph[node]:
            if nxt == target:
                return path + (target,)
            if nxt not in visited or visited[nxt] > nxt_days_infected:
                queue.append((nxt, nxt_days_infected, path + (nxt,)))
                visited[nxt] = nxt_days_infected

if __name__ == "__main__":
    graph = {
        0 : [1],
        1 : [0, 2], 
        2 : [1, 3], 
        3 : [2, 4, 5],
        4 : [3, 7], 
        5 : [3, 7],
        6 : [7, 9],
        7 : [4, 5, 6, 8],
        8 : [7, 9],
        9 : [6, 8],
    }
    virus_nodes = {4, 6, 7}
    max_survive_days = 2
    print(bfs(graph, virus_nodes, 0, 9, max_survive_days))
输出:

(0, 1, 2, 3, 5, 7, 6, 9)

解决这个问题最简单的方法是使用BFS,但你要从头开始

假设感染后的存活时间为TTL天

从目的地运行BFS,但你只能考虑在小于TTL长的路径上感染行星。一旦BFS到达TTL长度的路径,那么从那时起,你只能使用干净的行星,一直到开始


这是特别容易,如果你做的BFS一级一级。然后,您只需检查level是否在每个病例中感染后的存活时间发生变化?您好,对于每个示例,它都是相同的数字。我给你们举了两个例子,两张地图。在每张地图上都有携带病毒的行星。在特定地图上,数字与案例相同。在另一个例子中,这个数字是不同的。我认为你的解决方案并没有考虑被感染后的生存时间。如果在路径期间到达病毒星球(因为没有其他选项可用),您可以确定是否接受或拒绝该路径。虽然更新了答案,但在处理过程中(虽然您也可以检查完成的候选最短路径,以查看机组人员是否会在途中死亡,但这并没有那么有效。我认为Zarif是对的。下面是此算法的反例:假设有两条路径从源
s
到目标
t
,并且
x
是一条路径。)