一些知识
AOV网
一个无环的有向图称为有向无环图。有向无环图是描述一个工程、计划、生产、系统等流程的有效工具。一个大工程可以分为若干个子工程(活动),活动之间通常有一定的约束,例如先做什么活动、后做什么活动。
用顶点表示活动,用弧表示活动之间的优先关系的有向图,称为顶点表示活动的网,简称AOV网。
若顶点i到顶点j之间存在一条有向路径,称顶点i为顶点j的前驱,顶点j为顶点i的后继,若i,j是图中的弧,则顶点i是顶点j的直接前驱,顶点j是顶点i的直接后继。
AOV网中的弧表示活动之间存在制约关系(先后关系)。
例子就不说了,数据结构课都说过。
拓扑排序
拓扑排序是将AOV网中的顶点排成一个线性序列,该序列必须满足:若从顶点i到顶点j有一条路径,则该序列中顶点i一定在顶点j之前
注意:拓扑排序并不唯一
算法设计
(1)求出各顶点的入度,存入输出in[]中,并将入度为0的顶点入栈S。
(2)如果栈不为空,则重复执行以下操作:
①栈顶元素i出栈,并保存到拓扑序列数组topo[]中;
②顶点i的所有邻接点入度减1,如果减1后入度为0,则入栈。
(3)如果输出的顶点数小于AOV网的顶点数,则说明图中有环,否则输出拓扑序列。
代码如下:
#include
using namespace std;
const int N=1e5+5;
int n,m;
struct edge{
int to,next,w;
}e[N];
int head[N],in[N],topo[N],cnt;
stack<int>s;
inline void add(int u,int v){
e[cnt].to=v,e[cnt].next=head[u];
head[u]=cnt++;
}
inline bool topsort(){
int k=0;
for(int i=0;i<n;++i)
if(!in[i])s.push(i);
while(!s.empty()){
int u=s.top();s.pop();
topo[k++]=u;
for(int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(--in[v]==0)s.push(v);
}
}
if(k<n)return false;
return true;
}
int main(){
cin>>n>>m;
memset(head,-1,sizeof(head));memset(in,0,sizeof(in));
for(int i=0;i<m;++i){
int u,v;scanf("%d%d",&u,&v);
add(u,v);in[v]++;
}
if(!topsort())cout<<"该有向图有回路"<<endl;
else{
for(int i=0;i<n-1;++i)printf("%d ",topo[i]);
cout<<topo[n-1]<<endl;
}
}
例题:
题目描述
设G为有n个顶点的带权有向无环图,G中各顶点的编号为1到n,请设计算法,计算图G中1到n之间的最长路径。
输入格式
输入的第一行有两个整数,分别代表图的点数n和边数m。
第2到第(m+1) 行,每行 33 个整数 u, v, w(u 输出格式 若1与n不连通,请输出-1。 输入样例 输出样例 数据规模 分析 其实这道题用bellman_ford或者SPFA就能解答,当然也可以用拓扑排序来做,但是有一个细节需要注意: 代码如下:
输出一行一个整数,代表1到n的最长路。
2 1
1 2 1
1
1<=n<=1500,1<=m<=5×10^4,1<=u,v<=n,-10^5<=w<=10^5
题目要求1到n的最大值,但是对一个有向无环图来说,入度为0的点可不只是1这个点,那么我们不可能不处理他,如果不处理他,这些点的邻接点的入度永远不可能减为0,那样就无法处理了。但是直接入栈结果很可能不对!很可能就不是以1为起点的路径了。
处理方法是:把所有除了1之外的入度为0的点先入栈,然后做一系列出栈操作,把所有入度为0的点的邻接点的入度减1,相当于直接把除了1之外的入度为0的点全部处理了,这并不会影响最终结果,只是单纯避免了处理其他点。当然了,处理完这些点以后,这些点的邻接点入度减去1以后很可能造成其他的出现入度为0的情况,依旧要进行处理,那我们就用循环框住就好了。#include