【问题标题】:Yield the shortest path in state transistions在状态转换中产生最短路径
【发布时间】:2010-02-10 23:37:05
【问题描述】:

我正在尝试提出一种遍历树的算法,但我卡住了。

这是一个相当难的问题(与我问过的其他问题相比),所以我可能需要自己继续思考。但我想我会把它扔在这里。

我有以下类结构:

public class Transition
{
    // The state we are moving from.
    public String From { get; set; }
    // All the To states for this from
    public List<String>To { get; set; }
}

List<Transition> currentTransistions;

当 currentTransitions 完全填写时,它看起来像这样(对我来说):

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfTransition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Transition>
    <From />
    <To>
      <string>Not Done</string>
    </To>
  </Transition>
  <Transition>
    <From>Not Done</From>
    <To>
      <string>In Progress</string>
      <string>Deleted</string>
    </To>
  </Transition>
  <Transition>
    <From>Deleted</From>
    <To>
      <string>Not Done</string>
    </To>
  </Transition>
  <Transition>
    <From>In Progress</From>
    <To>
      <string>Done</string>
      <string>Ready For Test</string>
      <string>Deleted</string>
    </To>
  </Transition>
  <Transition>
    <From>Done</From>
    <To>
      <string>In Progress</string>
    </To>
  </Transition>
  <Transition>
    <From>Ready For Test</From>
    <To>
      <string>In Progress</string>
      <string>Done</string>
      <string>Deleted</string>
    </To>
  </Transition>
</ArrayOfTransition>

这里的想法是我已经映射了 TFS 工作项的状态转换。我现在需要的是一种方式来表达“给定当前状态,我如何到达另一个状态”。

理想情况下应该是这样的:

 foreach (string state in GetToFinalState(finalState, currentState, currentTransistions)
 {
     // Save the workitem at the state so we can get to the final state.
 }

GetToFinalState,必须有一种方法来计算最短路径并使用 C# 的 yield 功能为 foreach 语句一次提供一个。

我以前使用过 yield one,所以我想我可以解决这个问题。但是我不确定如何在找到最短路径的同时做到这一点(无需在函数中的每次重新计算)?

如果您已经阅读到这里,谢谢。如果您提供答案,那么非常感谢。

【问题讨论】:

  • @Vaccano:为了记录,您的示例图不是树。例如,它有循环(未完成 -> 已删除 -> 未完成)。根据定义,树不能有循环。具体来说,它是一个有向非加权图。 定向,因为存在从 A 到 B 的过渡并不意味着存在从 B 到 A 的过渡。未加权,因为没有分配给 a 的价值/成本/权重过渡和所有过渡都被平等对待。

标签: c# tree yield


【解决方案1】:

如果不计算最短路径并在整个过程完成后yielding 每个路径段,您将无法有效地做到这一点。最短路径问题的性质不适用于有效计算此类部分解决方案的算法。

由于转移图没有加权,您可以简单地在其上运行BFS 来计算最短路径。你需要做这样的事情(我不确定 TFS 对象的属性,所以这只是一个伪代码):

IEnumerable<string> ShortestPath(string fromState, string toState, Transition[] currentTransitions) {
    var map = new Dictionary<string, string>();
    var edges = currentTransitions.ToDictionary(i => i.From, i => i.To);
    var q = new Queue<string>(); 
    map.Add(fromState, null);
    q.Enqueue(fromState);
    while (q.Count > 0) {
        var current = q.Dequeue();
        foreach (var s in edges[current]) {
            if (!map.ContainsKey(s)) {
                map.Add(s, current);
                if (s == toState) {
                    var result = new Stack<string>();
                    var thisNode = s;
                    do {
                        result.Push(thisNode);
                        thisNode = map[thisNode];
                    } while (thisNode != fromState);
                    while (result.Count > 0)
                        yield return result.Pop();
                    yield break;
                }
                q.Enqueue(s);
            }
        }
    }
    // no path exists
}

【讨论】:

  • 我正在尝试找出代码(感谢您发布它)。我对visited 对象感到困惑。那是什么?
  • @Vaccano:我将它的其他实例重命名为map。忘记重命名那个了。会编辑。这就是您在 Stack Overflow 文本框中而不是在 VS 或可以测试的地方编写代码时得到的结果。
  • 仅供参考,当前版本无法编译。它说你不能分配 s 因为它是 foreach 变量。 (它抱怨的行是s = map[s];)
  • @Vaccano:已修复。让我知道它是否有效。我对此进行了更新以优化算法,这样您在找到最终状态后就不会费心查看图表。 “过早的优化是万恶之源”
  • @Vaccano:谢谢!这是一个经典的 BFS 实现,没什么创意!不过,这样做通常不是一个好主意。您应该根据帖子的质量而不是作者对帖子进行投票 - Stack Overflow 中的投票欺诈检测机制可能会将其视为投票欺诈并取消您的投票。
【解决方案2】:

如果您需要在无环树中找到从节点到后代节点的最短路径,那么 Mehrdad 的解决方案是一个不错的解决方案。即先进行广度优先搜索,直到找到目的节点,然后计算出从起始节点到目的节点的路径。

如果您的图不是(非循环)树,而是任意加权图,那么朴素的广度优先搜索不起作用。它要么进入无限循环(如果你不聪明地跟踪你已经看到一个节点的时间),要么不能保证找到最小权重路径。

如果您处于这种情况,那么一个好的算法就是著名的“A*”算法。我在这里有一些关于如何在 C# 中实现 A* 的注释:

http://blogs.msdn.com/ericlippert/archive/tags/AStar/default.aspx

如果您有一个“估计功能”可以猜测最短路径上最有可能的下一个节点是什么,这将特别有用。

【讨论】:

  • "如果你的图不是无环树,而是任意图,那么朴素的广度优先搜索不起作用。要么进入无限循环,要么无法保证找到最短路径。”我很确定 BFS 可以在 任意图(不考虑周期)上工作,只要它们未加权。
  • 哇!我不知道无环树是什么。我用 Mehrdad 的解决方案尝试了几个例子,每次都是正确的。所以我要这么做。 (很明显,关于树木的知识比我所知道的要多得多。)谢谢你的回答。
  • @Mehrdad:我担心的是 BFS 不会跟踪“我以前来过这里”,因此可以立即进入一个循环并继续运行。很容易意外使用 BFS,该 BFS 是假设具有图的树形拓扑并运行到无穷大的。但是现在我想起来了,你是对的,假设你解决了循环问题,广度优先搜索确实可以让你在未加权的图中找到最短路径。我会更新文字。
  • @Vaccano:图是一组节点,它们之间有(可能是单向的,或“有向的”)边。图可以在其边中包含循环。树是一种特殊的图。特别是,树是有向的(父母指向孩子)并且永远不会有循环。
  • @Eric:不需要定向树。它被具体定义为一个连接的无环图。
猜你喜欢
  • 1970-01-01
  • 2018-05-03
  • 1970-01-01
  • 1970-01-01
  • 2022-08-18
  • 1970-01-01
  • 1970-01-01
  • 2020-09-12
  • 1970-01-01
相关资源
最近更新 更多