DAG图:有向无环图,是描述一项工程或系统的进行过程的有效工具。(一个有向无环图的拓扑序列一一定包含图中所有顶点)
一般的工程可以分为若干个活动,而这些活动之间存在着某种约束条件,也就是说某一项工程的进行必须在另一项工程的完成的前提之下完成。比如说:只有学完高数和C语言才能学数据结构。(不然学不会)2333
AOV网:用顶点表示活动,用弧表示活动中的优先关系的有向图,也称为顶点表示活动的网。
(这里书中讲到几个概念:前驱,后继,直接前驱,直接后继)
AOV网中不能够出现环路,因为如果那样就说明某一项活动的完成是自身的进行的前提。
对于一个DAG图来说,经过拓扑排序得到的拓扑序列并不是唯一的。只要序列满足代表某一事件的前提的点一定在代表这个事件的点的前面即可。
下面就来说一下拓扑排序的过程:
1)在有向图中选一个无前驱的结点(入度为零的点),将这个点输出。
2)在图中删除这个顶点和以它为尾的弧。(入度是这条弧的点)
3)重复1)2),直到图中没有入度为零的点为止。
4)如果此时输出的顶点数小于有向图中的顶点总数,说明有向图中是存在环的。(仅仅由一个环构成的图是没有入度为零的点的)
需要引入的辅助数据结构:
1)一堆数组indegree[],储存点的入度。入度为零的点就是indegree为零的点,删除入度为零的点只需要将弧头顶点入度减一。
2)栈S:暂存入度为零的点,这样可以避免重复扫描数组indegree[]检测入读为零的点。
3)一堆数组topo[]记录拓扑序列顶点的编号。
算法步骤:
1)求出各顶点的入度的存入indegree[]数组中,并将入度为零 的顶点入栈。
2)只要栈不为空,重复以下操作:
将栈顶元素vi出栈并保存在topo[]数组中。
对vi的各个邻接点入度减一,如果vk的入度为零就将其入栈。
3)如果最终输出的定点数少于顶点总数,则存在环,拓扑排序失败。否则拓扑排序成功。
#include <iostream>
#include <stack>
#include<limits.h>
using namespace std;
stack <int> sta;
int graph[13][13]={0};
int degree[13]= {0};
int topo[13];
int m;
void CreatG()
{
int a,b;
cin>>m;
for(int i=1; i<=m; i++)
{
cin>>a>>b;
graph[a][b]=1;
}
}
void Degree()
{
for(int i=1; i<=12; i++)
{
for(int j=1; j<=12; j++)
{
if(graph[i][j]==1)
{
degree[j]++;
}
}
}
}
void Topo()
{
int cnt=0;
for(int i=1; i<=12; i++)
{
if(degree[i]==0)
{
sta.push(i);
}
}
while(!sta.empty())
{
topo[++cnt]=sta.top();
int temp=sta.top();
degree[temp]=INT_MAX;//防止已经存入拓扑序列中的点影响后来入度为0的点进栈的操作
sta.pop();
for(int p=1; p<=12; p++)
{
if(graph[temp][p]==1)
{
degree[p]--;//已经入栈的点的邻接点的入度减一
if(degree[p]==0)
{
sta.push(p);
}
}
}
}
}
void Print()
{
cout<<topo[1];
for(int i=2; i<=12; i++)
{
cout<<"->"<<topo[i];
}
cout<<endl;
}
int main()
{
CreatG();
Degree();
Topo();
Print();
return 0;
}
自己写的代码,只能输出一种拓扑序列,有待改进。(形式类似于深度优先搜索)