拓扑排序(可判断是否有环(正环负环无所谓))
数据结构AOE网 和AOV-网一节
意义就是:
给出一些事件和活动 (图),该事件进行的前提条件是,所有以该事件为后继的活动已经完成(顶点进行的前提条件是,其作为后继的边全部完成)
给这些事件排个序,使得事件进行过程不冲突
如果冲突
存在一个环
否则
可以得到一个拓扑序列,并且还可以计算对应事件或者边的最早发生事件和最晚发生时间。
代码实现:
/*
拓扑排序
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#include<stack>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1010;
struct Edge
{
int v;
int val;
int next;
Edge()
{
next=-1;
}
} edge[maxn]; //边的个数
int head[maxn];
int Indegree[maxn];
int seque[maxn];
int beg_time[maxn],end_time[maxn];
bool GetTuopu(int n,struct Edge edge[],int head[],int Indegree[],int seque[])//给邻接表 和入度序列 得到拓扑序列
{
stack<int>mmp;
for(int i=0; i<n; i++)
if(!Indegree[i])
mmp.push(i);
int top=0;
while(!mmp.empty())
{
int now_v=mmp.top();
mmp.pop();
seque[top++]=now_v;
int to=head[now_v];
while(~to)
{
Indegree[edge[to].v]--;
if(!Indegree[edge[to].v])
{
mmp.push(edge[to].v);
}
to=edge[to].next;
}
}
if(top!=n)
return 0;
return 1;
}
int main()
{
int n,m,u,v,w;
while(~scanf("%d %d",&n,&m))
{
/*----------------建立邻接表------------*/
memset(head,-1,sizeof(head));
memset(Indegree,0,sizeof(Indegree));
for(int i=0; i<m; ++i)
{
scanf("%d %d %d",&u,&v,&w);
Indegree[v]++;
edge[i].v=v;
edge[i].next=head[u];
head[u]=i;
edge[i].val=w;
}
/*----------------求拓扑序列------------*/
if(!GetTuopu(n,edge,head,Indegree,seque))
{
printf("Tuop sequen not exit\n");
continue;
}
/*----------------求事件的最早开始时间------------*/
memset(beg_time,0,sizeof(beg_time));
for(int i=0; i<n; i++)//
{
int now_v=seque[i];
// beg_time[k]=Max(前驱的最短时间+边权)
int to=head[now_v];
while(~to)
{
if(beg_time[now_v]+edge[to].val>beg_time[edge[to].v])
beg_time[edge[to].v]=beg_time[now_v]+edge[to].val;
to=edge[to].next;
}
}
/*----------------求事件的最晚开始时间------------*/
for(int i=0; i<n; ++i)
end_time[i]=beg_time[n-1];//给事件的结束时间赋初值
for(int i=n-1; ~i; --i)//
{
int now_v=seque[i];
// end_time[k]=Min(后继的最晚时间-边权)
int to=head[now_v];
while(~to)
{
if(end_time[now_v]>end_time[edge[to].v]-edge[to].val)
end_time[now_v]=end_time[edge[to].v]-edge[to].val;
to=edge[to].next;
}
}
for(int i=0; i<n; ++i)
printf("%3d",i);
printf("\n");
printf("beg_time:\n");
for(int i=0; i<n; ++i)
printf("%3d",beg_time[i]);
printf("\n");
printf("end_time:\n");
for(int i=0; i<n; ++i)
printf("%3d",end_time[i]);
printf("\n");
/*
边的最早开始时间:前驱的最早开始时间
边的最晚开始时间:后继的最晚开始时间-边权
*/
}
}
/*
测试数据
9 11
0 1 6
0 2 4
0 3 5
1 4 1
2 4 1
3 5 2
4 6 9
4 7 7
5 7 4
7 8 4
6 8 2
*/