zoukankan      html  css  js  c++  java
  • 拓扑排序

    拓扑排序练习

    题目要求:

    学习课程计划的辅助编排系统

    总结起来基本要求如下:

    1. 建立构造课程的有向无环图,求解拓扑子集的划分

    2. 对拓扑子集划分的结果可以进行调整,以适度拉长修业的时间,避免学生负担过重

    实现提示:

    将有向无环图中的顶点集划分成若干互不相交的子集
    S1,S2,…,Sm,使得任意两个有弧相连的顶点分属不同的子集,并且,若〈j,k〉是一条从顶
    点j 到顶点k 的有向弧,j∈Sp ,k ∈Sq,则子集的序号必有p<q。每个子集Si (i=1,2,…,m)
    中的顶点为同一学期中开设的课程。

    例如根据一个简单的优先关系模型,所得出的划分实例如下:

    提示:

    拓扑子集划分的算法是拓扑排序算法的拓展,可以设置两个栈来处理子集的划分。一个
    栈用来存放当前入度为零的顶点,另一个栈则用来存放新产生的入度为零的顶点,作备用栈。
    交替使用这两个栈,当第一个栈退空时,启用备用栈作为当前栈,而那退空的栈就充当备用
    栈,继续存放新产生的入度为零的顶点。事实上,同一个栈里存放的顶点即属于同一个子集,
    也就是可在同一个学期开设的课程。

    以上,是题目要求。

    按步骤解答:

    1. 建立图,用邻接表存储图,文件读入图的基本信息。

    2. 先不考虑学分限制的问题,按照提示修改拓扑排序算法,求解拓扑子集的划分。

    先上代码:

     1 void TopsortbyStack(Graphl& G)
     2 {
     3     using std::stack;
     4     stack <int > S1, S2;    //两个栈,交替使用,当前栈,备用栈
     5     int i;
     6     int flag;    //设置一个标志位,表示当前栈是S1或是S2
     7     //入度为0的顶点入栈
     8     for( i = 0; i < G.VerticesNum() ; i ++)
     9     {
    10         if ( G.Indegree[i] == 0 )
    11             S1.push( i);
    12     }
    13     cout<<endl;
    14     flag = 1;    // 标志位为1表示当前栈为S1,标志位为2表示当前栈为2
    15     while( (flag == 1 && !S1.empty()) || (flag == 2 && !S2.empty()) )
    16     {
    17         if( flag == 1 )
    18         {
    19             int v = S1.top();
    20             S1.pop();
    21             cout<< v<< "   ";
    22             G.Mark[v] = VISITED;
    23             for ( Edge e = G.FirstEdge(v); G.IsEdge(e); e = G.NextEdge(e) )
    24             {
    25                 G.Indegree[ G.ToVertex(e) ] --;
    26                 if( G.Indegree[ G.ToVertex( e ) ] == 0 )
    27                     S2.push(G.ToVertex(e));
    28             }
    29             //当前栈为空,则交替
    30             if ( S1.empty())
    31             {
    32                 flag = 2;
    33                 cout<< endl;
    34             }
    35         }
    36         else
    37         {
    38             int v = S2.top();
    39             S2.pop();
    40             cout<< v<< "   ";
    41             G.Mark[v] = VISITED;
    42             for ( Edge e = G.FirstEdge(v); G.IsEdge(e); e = G.NextEdge(e) )
    43             {
    44                 G.Indegree[ G.ToVertex(e) ] --;
    45                 if( G.Indegree[ G.ToVertex( e ) ] == 0 )
    46                     S1.push(G.ToVertex(e));
    47             }
    48             //当前栈为空,则交替
    49             if ( S2.empty())
    50             {
    51                 flag = 1;
    52                 cout<< endl;
    53             }
    54         }
    55     }
    56 }

    使用一个flag标志表示当前栈和备用栈的选择,感觉代码有点多。

    另一个方案是一直使用S1作为当前栈,代码能够简洁一点,但是这样就需要设置一个临时栈,来实现栈的交换,不知道哪种方法更快一点。

    运行结果显示(顶点从0开始计数):

    3. 接下来考虑学分限制的问题

    为每个顶点添加学时属性,Hours

    1 int * Hours;                //存放图中顶点的学时

    思路是:从当前栈弹出最上面的那个顶点之前,先计算下本学期已经修的学时,与之相加后与280学时比较,如果比较结果小于280学时,则弹出后继续循环;

    如果比较结果大于280学时,则将当前栈中剩下的元素都弹出并送进备用栈中;

     1     if( flag == 1 )
     2         {
     3             int v = S1.top();
     4             tph = tph + G.Hours[v];
     5             if ( tph <= hour)  //如果比较结果小于280学时,则弹出后继续循环
     6             {
     7                 S1.pop();
     8                 cout<< v<< "   ";
     9                 G.Mark[v] = VISITED;
    10                 for ( Edge e = G.FirstEdge(v); G.IsEdge(e); e = G.NextEdge(e) )
    11                 {
    12                     G.Indegree[ G.ToVertex(e) ] --;
    13                     if( G.Indegree[ G.ToVertex( e ) ] == 0 )
    14                         S2.push(G.ToVertex(e));
    15                 }
    16                 //当前栈为空,则交替
    17                 if ( S1.empty())
    18                 {
    19                     flag = 2;
    20                     tph = 0;
    21                     cout<< endl;
    22                 }
    23             }
    24             else      //如果比较结果大于280学时,则将当前栈中剩下的元素都弹出并送进备用栈中
    25             {
    26                 while(!S1.empty())
    27                 {
    28                     int temp = S1.top();
    29                     S1.pop();
    30                     S2.push(temp);
    31                 }
    32                 flag = 2;
    33                 tph = 0;
    34                 cout<< endl;
    35             }
  • 相关阅读:
    帧锁定同步算法
    为 Raft 引入 leader lease 机制解决集群脑裂时的 stale read 问题
    etcd:从应用场景到实现原理的全方位解读
    给定一个二叉搜索树(BST),找到树中第 K 小的节点
    UDP如何实现可靠传输
    理解TCP/IP三次握手与四次挥手的正确姿势
    Redis持久化
    Redis提供的持久化机制(RDB和AOF)
    redis渐进式 rehash
    redis rehash
  • 原文地址:https://www.cnblogs.com/13062225wmx/p/5987075.html
Copyright © 2011-2022 走看看