拓扑排序(Topological order)

#include
#define INF 99999999 
using namespace std;
/*
    AOV: 
        一个较大的工程往往被划分成许多子工程,我们把这些子工程称作活动(activity)。在整个工程中,有些子工
        程(活动)必须在其它有关子工程完成之后才能开始,也就是说,一个子工程的开始是以它的所有前序子工程的
        结束为先决条件的,但有些子工程没有先决条件,可以安排在任何时间开始。为了形象地反映出整个工程中各
        个子工程(活动)之间的先后关系,可用一个有向图来表示,图中的顶点代表活动(子工程),图中的有向边代表
        活动的先后关系,即有向边的起点的活动是终点活动的前序活动,只有当起点活动完成之后,其终点活动才能
        进行。通常,我们把这种顶点表示活动、边表示活动间先后关系的有向图称做顶点活动网(Activity On Vertex network),简称AOV网。
    特点:
        AOV网络若有合理的拓扑序,则它是一个有向无环图。
        有向:边从先完成的活动指向后完成的活动。
        无环:易知如果AOV网络中存在环,则回路上的所有活动都无法进行 
*/

/*
    拓扑排序:
        把AOV网络中的所有活动排列成一个线性序列,使得每个活动的所有前驱活
        动都排在该活动的前面,我们把此序列叫做拓扑序列(Topological order)。 
*/

/*
    算法:
        普通:
            循环 n次,每次循环找出入度为 0的点,并把该点所有边删除。 
                在两种图中找入度为 0的点都是O(V)级复杂度,所以两种图总复杂度都是O(V方) 

        改进:
            1)初始化时把所有结点的入度求出来,并放在容器中 
            2)每次从容器中拿出一个结点,和他有边的结点入度减1,如果减1后入度为0加入容器中
            3)加入容器和从容器中取出都是拓扑排序,取一个就行
                第一步在矩阵图中时间复杂度为 O(V方),在链式图中为 O(E)
                所以在链式图中总复杂度为O(V) + O(E),矩阵图为O(V方) 

        实现: 
            下面的代码实现的是改进后的算法。
            有权图无权图对拓扑排序无影响,代码使用有权图实现的。因为还有一个类似的AOE网络需要图有权值 
*/ 

class MGraph                //矩阵图 
{
    public:
        int n;
        int **matrix;
        MGraph(){ matrix = NULL; }
};
class Node              //链式图 
{
    public:
        int n;
        int ew;
        Node(int tn, int tw){ n = tn; ew = tw; }
};
class LGraph
{
    public:
        vector *vs;
        int n;
        LGraph(){ vs = NULL; }
};
MGraph* create_mGraph()
{
    int i, from, to, w, vn, en;     //点数、边数、边权 
    MGraph *g = new MGraph();
    scanf("%d%d", &vn, &en);
    g->n = vn;
    g->matrix = new int*[vn];
    for(i = 0; i < vn; i++)
    {
        g->matrix[i] = new int[vn];
        fill(g->matrix[i], g->matrix[i] + vn, INF);
        g->matrix[i][i] = 0; 
    }
    for(i = 0; i < en; i++)
    {
        cin >> from >> to >> w;
        g->matrix[from][to] = w;    //必须是有向图 
    }
    return g;
}
LGraph *create_lGraph()
{
    int i, from, to, w, vn, en;     //点数、边数、边权 
    LGraph *g = new LGraph();
    scanf("%d%d", &vn, &en);
    g->n = vn;
    g->vs = new vector[vn];
    for(i = 0; i < en; i++)
    {
        cin >> from >> to >> w;
        Node *temp = new Node(to, w);
        g->vs[from].push_back(*temp);   //必须是有向图 
    }
    return g;
}

bool topSortM(MGraph *g, int *topOrder)
{
    int  n = g->n, countt = 0, i, j, cnt = 0;
    int *arr = new int[n], *inDegree = new int[n];
    memset(inDegree, 0, n*sizeof(int));
    for(i = 0; i < n; i++)
        for(j = 0; j < n; j++)      //O(V方)
            if(g->matrix[i][j] != INF && g->matrix[i][j] != 0)
                inDegree[j]++;
    for(i = 0; i < n; i++)      //入度为0的进容器 
        if(inDegree[i] == 0)
            arr[countt++] = i;
    while(countt != 0){
        int out = arr[--countt];    //出容器时记录序列 
        topOrder[cnt++] = out;
        for(i = 0; i < n; i++)
            if(g->matrix[out][i] != INF && g->matrix[out][i] != 0
                     && --inDegree[i] == 0)     //删除相应的边 
                arr[countt++] = i;      //入度为0的进容器 
    }
    if(cnt != n)
        return false;       //图有环 
    return true;
}

bool topSortL(LGraph *g, int *topOrder)
{
    int n = g->n, countt = 0, i, j, cnt = 0;
    int *arr = new int[n], *inDegree = new int[n];
    memset(inDegree, 0, n * sizeof(int));
    for(i = 0; i < n; i++)      //O(E)
        for(j = 0; j < g->vs[i].size(); j++)
            inDegree[g->vs[i][j].n]++;
    for(i = 0; i < n; i++)          //入度为0的进容器 
        if(inDegree[i] == 0)
            arr[countt++] = i;
    while(countt != 0)
    {
        int out = arr[--countt];        //出容器时记录序列 
        topOrder[cnt++] = out;  
        for(j = 0; j < g->vs[out].size(); j++)
            if(--inDegree[g->vs[out][j].n] == 0)    //删除相应的边且入度为0的进容器  
                arr[countt++] = g->vs[out][j].n;
    }
    if(cnt != n)
        return false;
    return true;
} 
int main()
{
    LGraph *lg = create_lGraph();
    MGraph *mg = create_mGraph();
    int *topM = new int[mg->n]; 
    int *topL = new int[lg->n]; 
    topSortL(lg, topL);
    topSortM(mg, topM);
    for(int i = 0; i < mg->n; i++)
        cout << topM[i] << " "; 
    cout << endl;
    for(int i = 0; i < lg->n; i++)
        cout << topL[i] << " "; 
    return 0;
}
/*
    input:
        5 6 
        0 1 1
        0 2 2
        0 3 1
        1 2 1
        2 4 1
        3 4 1
        5 6 
        0 1 1
        0 2 2
        0 3 1
        1 2 1
        2 4 1
        3 4 1
    output:
        0 3 1 2 4
        0 3 1 2 4
*/

你可能感兴趣的:(DSA)