在现实中,我们经常会遇到如图所示问题
这张图指明了想要完成指定的任务所需完成的前置任务。这种问题叫做调度问题。我们需要得知如何安排才能使得所有任务顺利完成。这就叫做优先级限制下的调度问腿
拓扑排序:给定一副有向图,将所有顶点排序,使得所有有向边均从排在前面的元素指向排在后面的元素
要解决调度问题,首先我们需要确定图中有没有环。很明显,当有向图种存在环时,调度问题是无解的。
有向环检测
//寻找有向环
class directedcycle
{
public:
directedcycle(digraph g)
{
marked = new bool(g.numv());
edgeto = new int(g.numv());
onstack = new bool(g.numv());
for (unsigned int v = 0; v < g.numv(); v++)
{
if (!marked[v])
dfs(g,v);
}
}
bool has_cycle()
{
return !cycle.empty();
}
private:
bool *marked;
int *edgeto;
bool *onstack;
std::vector<int> cycle;
void dfs(digraph g, int v)
{
onstack[v] = true;
marked[v] = true;
for (auto w : g.iterator(v))
{
if (has_cycle())
return;
else if (!marked[v])
{
edgeto[w] = v;
dfs(g, w);
}
else if (onstack)
{
for (int i = v; i != w; i = edgeto[i])
{
cycle.push_back(i);
}
cycle.push_back(w);
cycle.push_back(v);
}
}
onstack[v] = false; //如果走到这一步说明从v出发搜索完成所有的子节点,需要回退,可以将v设置为不在遍历中了
}
};
这个算法的原理其实挺简单的,主要思想还是深度优先算法,只不过我们会把走过的路径记住,并在每次调用dfs方法是查看我们是否走到正在遍历中的点
有向图中基于深度优先搜索的顶点排序
我们其实可以直接使用深度优先搜索来对有向无环图进行排序。
//基于深度优先搜索的顶点排序
class DFO
{
private:
bool *marked;
std::vector<int> pre;
std::vector<int> post;
std::vector<int> revers_post;
void dfs(digraph g, int v)
{
pre.push_back(v);
marked[v] = true;
for (int i=0;i<g.iterator(v).size();i++)
{
int w = g.iterator(v)[i];
if (!marked[w])
{
dfs(g, w);
}
//printf("?");
}
//printf("#%d", v);
post.push_back(v);
revers_post.push_back(v);
}
public:
DFO(digraph g)
{
marked = new bool[g.numv()];
std::fill(marked, marked + g.numv(), 0);
for (unsigned int v = 0; v < g.numv(); v++)
{
if (!marked[v])
{
dfs(g, v);
}
}
}
std::vector<int> pre_order()
{
return pre;
}
std::vector<int> post_order()
{
return post;
}
std::vector<int> rp_order()
{
std::reverse(revers_post.begin(), revers_post.end());
return revers_post;
}
};
拓扑排序
std::vector<int> topo(digraph g)
{
std::vector<int> order;
directedcycle cyclefinder(g);
if (!cyclefinder.has_cycle())
{
DFO dfs(g);
order = dfs.rp_order();
}
return order;
}