拓扑排序(可判断是否有环(正环负环无所谓))

版权声明:转载请注明出处哦。 https://blog.csdn.net/Dch19990825/article/details/83046527

数据结构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
*/

猜你喜欢

转载自blog.csdn.net/Dch19990825/article/details/83046527