a.简介:
拓扑排序主要用来解决满足一个给定图的各个结点的顺序问题。因此如何从实际问题中抽象出图是解决问题的关键。
b.主要步骤:
1.选择当前入度为0的节点,去除;
2.删除以上一节点为头的约束边;
3.递归以上两步直到删除图中所有节点。
c.注意事项:
1.清晰题中所描述的问题是否满足拓扑排序的要求;
2.将题中的事物(人,城市等)抽象成点,事物之间的关系抽象成边;
3.构建图:判断使用拓扑还是反拓扑,应结合题意,一般正向约束条件较多或无法判断开始的多个0入度点时;(具体问题之中边为有向边)
4.存图:选择合适的方式存图,节点少时用邻接矩阵,多时用邻接表存图时要注意两种方式的区别:邻接矩阵需要考虑多重边对入度的影响,而邻接表则不用;
5.判断题意是否涉及死环问题:死环判定条件:若排序后删除的节点数不等于所给图的节点数,则必存在环;
6.如果题中提到集合(许多元素具有同一性质)的问题:考虑并查集和并元素,如:两个人成绩相同,一个班级等;
7.常用方法:拓扑常用邻接表,队列,邻接矩阵,栈等数据结构相互结合存储,实际情况中要灵活运用。
代码如下:
邻接矩阵:
void topo(int n)//n个节点的图
{
for(int i=1;i<=n;++i)//循环加入n个节点
{
int k;//记录所选点标号
for(int j=1;j<=n;++j)//选择入度为0的节点
{
if(!ideg[j])
{
k=j; break;
}
}
ord[i]=k; ideg[k]=-1;//去除此点
for(int j=1;j<=n;++j)//去除所有关联边
{
if(ideg[j]>0&&map[k][j])
{
--ideg[j];
}
}
}
}
邻接矩阵+队列(可用优先队列)
void topo(int n)
{
queue<int> que; stack<int> sta;
for(int i=1;i<=n;++i)
{
if(!ideg[i])
{
que.push(i); ideg[i]=-1;
}
}
while(!que.empty())
{
int now=que.front(); que.pop();
sta.push(now);//只是举个例子 可用数组
for(int i=1;i<=n;++i)
{
if(map[now][i]&&ideg[i]>0)
{
--ideg[i];
if(!ideg[i])//此处应注意是now的邻接点
{
que.push(i); ideg[i]=-1;
}
}
}
}
}
邻接表+优先队列:
void topo(int n)
{
queue<int,vector<int>,greater<int> > que;
for(int i=1;i<=n;++i)
{
if(!ideg[i])//入队即标记
{
que.push(i); ideg[i]=-1;
}
}
cnt=0;
while(!que.empty())
{
int now=que.top(); que.pop();//去除节点
ord[++cnt]=now;//保存序列
for(int i=head[now];i!=-1;i=edge[i].next)
{
int go=edge[i].to;//区分go与i
if(ideg[go]>0) --idge[go];
if(!idge[go])//入队即标记 一个点不能两次入队
{
que.push(go); idge[go]=-1;
}
}
}
}