Donald Knuth 撰写了这篇论文 A Structured Program to Generate all Topological Sorting Arrangements。这篇论文最初发表于 1974 年。论文中的以下引用使我对这个问题有了更好的理解(在文本中,关系 i
解决这个问题的一个自然方法是让 x1 成为
没有前辈的元素,然后删除所有关系
从 x12 成为一个元素 ≠
x1 在系统中没有前任,因为它现在存在,
然后删除 x2only 方法,因为 x1 必须是一个元素
没有前任,并且 x2 必须没有前任
当所有关系 x1所有的算法
拓扑排序问题的解决方案;这是一个典型的例子
“回溯”程序,在每个阶段,我们都考虑一个
来自“找到所有方法来完成给定部分
排列 x1x2...xk 到 a
拓扑排序 x1x2...xn 。”
一般方法是对所有可能的选择进行分支
xk+1.
回溯应用程序的一个核心问题是
找到一种合适的方式来排列数据,以便于
对 xk+1 的可能选择进行排序;在这
如果我们需要一种有效的方法来发现所有元素的集合≠
{x1,...,xk} 没有其他前任
比 x1,...,xk,并保持这个知识
当我们从一个子问题转移到另一个子问题时,效率很高。
本文包含一个高效算法的伪代码。每个输出的时间复杂度为 O(m+n),其中 m 是输入关系的数量,n 是字母的数量。我编写了一个 C++ 程序,它实现了论文中描述的算法——维护变量和函数名称——它将你问题中的字母和关系作为输入。我希望没有人抱怨给程序提供这个答案——因为与语言无关的标签。
#include <iostream>
#include <deque>
#include <vector>
#include <iterator>
#include <map>
// Define Input
static const char input[] =
{ 'A', 'D', 'G', 'H', 'B', 'C', 'F', 'M', 'N' };
static const char crel[][2] =
{{'A', 'B'}, {'B', 'F'}, {'G', 'H'}, {'D', 'F'}, {'M', 'N'}};
static const int n = sizeof(input) / sizeof(char);
static const int m = sizeof(crel) / sizeof(*crel);
std::map<char, int> count;
std::map<char, int> top;
std::map<int, char> suc;
std::map<int, int> next;
std::deque<char> D;
std::vector<char> buffer;
void alltopsorts(int k)
{
if (D.empty())
return;
char base = D.back();
do
{
char q = D.back();
D.pop_back();
buffer[k] = q;
if (k == (n - 1))
{
for (std::vector<char>::const_iterator cit = buffer.begin();
cit != buffer.end(); ++cit)
std::cout << (*cit);
std::cout << std::endl;
}
// erase relations beginning with q:
int p = top[q];
while (p >= 0)
{
char j = suc[p];
count[j]--;
if (!count[j])
D.push_back(j);
p = next[p];
}
alltopsorts(k + 1);
// retrieve relations beginning with q:
p = top[q];
while (p >= 0)
{
char j = suc[p];
if (!count[j])
D.pop_back();
count[j]++;
p = next[p];
}
D.push_front(q);
}
while (D.back() != base);
}
int main()
{
// Prepare
std::fill_n(std::back_inserter(buffer), n, 0);
for (int i = 0; i < n; i++) {
count[input[i]] = 0;
top[input[i]] = -1;
}
for (int i = 0; i < m; i++) {
suc[i] = crel[i][1]; next[i] = top[crel[i][0]];
top[crel[i][0]] = i; count[crel[i][1]]++;
}
for (std::map<char, int>::const_iterator cit = count.begin();
cit != count.end(); ++cit)
if (!(*cit).second)
D.push_back((*cit).first);
alltopsorts(0);
}