我会尽力解释算法应该做什么:
有一类“食谱”。每个食谱可以包括其他食谱,但不能包括自己或包含它的任何其他食谱。
所以,一个简单的例子就是我们只有两个食谱A&乙
如果A先添加B,那么稍后B就不能添加A,因为它会导致循环。
更复杂的例子是:
A,B,C
(1)食谱C添加B
(2)配方B添加A
(3)配方A试图添加C,但由于这种关系不能。 C - B - A.
我自己可以这样做,我只是想知道这是否是一个标准命名算法,我可以抓住最佳解决方案。
由于
答案 0 :(得分:7)
在数学/计算机科学术语中,您的结构称为directed graph。你想要一个“Directed Acyclic Graph” - 就是没有循环的那个。
要确定图表中是否存在周期,您可以使用名为 Topological sorting 的算法。它试图重新排列图形,这样如果A指的是B,那么A总是按顺序出现在B之前。如果图表有周期,它会停止。
如果您想在图表中找到所有周期(这对错误消息有帮助),那么 this stackoverflow question and answer 可以提供很多帮助。
作为背景:
图形 =具有通过边链接的节点的任何东西(在您的情况下节点是配方,参考是边)。
定向 =边缘有方向。在你的情况下,这是真的,因为'A'指的是'B',而不是'A'和'B'彼此。
答案 1 :(得分:3)
Topological ordering /循环检测? (如果检测到循环,则拓扑排序算法停止。)
这应该与你正在做的事情很接近。
答案 2 :(得分:1)
鉴于你的条件,我认为你最终会得到的结构是DAG。
因此,如果是,我们可以找出添加新节点是否创建周期然后我们不添加它,否则我们添加它。
class Foo
{
public List<Foo> Reachables { get; set; }
public Foo()
{
this.Reachables = new List<Foo>();
}
public bool Add(Foo other)
{
this.Reachables.Add(other); // add it
if(other.IsReachable(this)) // then see if it create a cycle
{
this.Reachables.Remove(other); // if yes remove it
return false;
}
else
{
return true; // else keep it
}
}
private bool IsReachable(Foo goal)
{
// BFS
Queue<Foo> nextQueue = new Queue<Foo>();
List<Foo> traversed = new List<Foo>();
bool found = false;
nextQueue.Enqueue(this);
while (!found) {
Foo node = null;
try { node = nextQueue.Dequeue(); }
catch { break; }
traversed.Add(node);
if (node.Equals(goal)) {
found = true;
break;
}
else
{
foreach (Foo neighbor in node.Reachables)
if (!traversed.Contains(neighbor) && !nextQueue.Contains(neighbor))
nextQueue.Enqueue(neighbor);
}
}
return found;
}
}
class Program
{
static void Main(string[] args)
{
Foo A = new Foo();
Foo B = new Foo();
Foo C = new Foo();
Console.WriteLine(C.Add(B));
Console.WriteLine(B.Add(A));
Console.WriteLine(A.Add(C));
Console.WriteLine(C.Add(A));
}
}
输出:
True
True
False
True
答案 3 :(得分:0)