精华内容
下载资源
问答
  • 求关键路径

    千次阅读 多人点赞 2017-07-19 16:34:56
    一:概念:在学习关键路径前,先了解一个AOV网和AOE网的概念:如下所示 假如汽车生产工厂要制造一辆汽车,制造过程的大概事件和活动时间如上AOE网: 那么,显然对上AOE网而言,所谓关键路径:开始–>发动机...

    一:概念:

    在学习关键路径前,先了解一个AOV网和AOE网的概念:如下图所示
    这里写图片描述
    假如汽车生产工厂要制造一辆汽车,制造过程的大概事件和活动时间如上图AOE网:
    那么,显然对上图AOE网而言,所谓关键路径:

    开始–>发动机完成–>部件集中到位–>组装完成。路径长度为5.5。如果我们试图缩短整个工期,去改进轮子的生产效率,哪怕改动0.1也是无益的。只有缩短关键路径上的关键活动时间才可以减少整个工期的长度。

    例如如果制造发动机缩短为2.5天,整车组装缩短为1.5天,那么关键路径为4.5。工期也就整整缩短了一天时间。

    好吧! 那么研究这个关键路径意义何在?
    假定上图AOE网中弧的权值单位为小时,而且我们已经知道黑深色的那一条为关键路径。假定现在上午一点,对于外壳完成事件而言,为了不影响工期:外壳完成活动最早也就是一点开始动工,最晚在两点必须要开始动工。最大权值3表示所有活动必须在三小时之后完成,而外壳完成只需要2个小时。所以,这个中间的空闲时间有一个小时,为了不影响整个工期,它必须最迟两点动工。

    那么才可以保证3点时与发动机完成活动同时竣工,为后续的活动做好准备。

    二:相关术语:

    1. AOV网络(Activity On Vertex Network):有向图,用顶点表示活动,用弧表示活动的先后顺序
    2. AOE网络(Activity On Edge):有向图,用顶点表示事件,用弧表示活动,用权值表示活动消耗时间(带权的有向无环图)
    3. 活动:业务逻辑中的行为,用边表示
    4. 事件:活动的结果或者触发条件
    5. 关键路径:具有最大路径长度(权重)的路径,可能不止一条
    6. 活动的两个属性:e(i)最早开始时间,l(i)最晚开始时间
    7. 事件的两个属性:ve(j)最早开始时间,vl(j)最晚开始时间

    这里写图片描述

    三:计算关键路径的过程:

    步骤:

    1. 先求出每个顶点的ve(最早开始时间)和vl(最晚开始时间)的值
    2. 通过这两个值就可以求出每条边的e(最早开始时间)和 l(最晚开始时间)值。
    3. 取e(i)=l(i)的边就是关键路径上的边,相连,就能得到关键路径(键路径可能不止一条)

    ①:求ve(j)的值(事件最早开始时间)

    1. 从前向后,直接前驱节点的ve值+当前节点的边的权值(有可能多条,取最大值)
    2. 第一个顶点的ve等于0
    顶点 V1 V2 V3 V4 V5 V6 V7
    ve(j) 0 3 2 6 7 5 10

    ②:求vl(j)的值(事件最迟开始时间)

    1. 从后向前(V9开始),直接后继节点的vl值-当前节点的边的权值(有可能多条,取最小值)
    2. 终结点的vl等于它的ve
    顶点 V1 V2 V3 V4 V5 V6 V7
    vl(j) 0 3 3 6 7 6 10

    ③:求e(i)的值(活动最早开始时间)

    1. e ( i ):活动ai是由弧< vk,vj >表示,则活动的最早开始时间应该和事件vk的最早发生时间相等,因此,就有e(i)=ve(k)。
      即:边(活动)的最早开始时间等于它发出的顶点(事件)的的最早发生时间
    a1(3) a2(6) a3(2) a4(4) a5(2) a6(1) a7(3) a8(1) a9(3) a10(4)
    e(i) 0 0 0 3 3 2 2 6 7 5

    ④:求l(i)的值(活动最晚开始时间)

    1. l ( i ):活动ai是由弧< vk,vj >表示,则ai的最晚发生时间要保证vj的最迟发生时间不拖后(vj最迟发生时间为9的话,ai的最迟时间就必须是 9-活动耗时 )。因此,l(i)=vl(i)-len< vk,vj >
      即:活动到达顶点的最晚发生时间减去边的权重
    a1(3) a2(6) a3(2) a4(4) a5(2) a6(1) a7(3) a8(1) a9(3) a10(4)
    l(i) 0 0 1 3 4 5 3 6 7 6

    ⑤:求出关键边和关键路径:

    1. 当e(i)==l(i),即:活动最早开始时间 = 活动最晚开始时间时,可以得到关键边为:
      a1 a2 a4 a8 a9

    2. 然后根据关键边组合成关键路径:
      a1->a4->a9 和 a2->a8->a9

    展开全文
  • #include "stdafx.h" #include"malloc.h" typedef int Status; typedef int InfoType;... printf("以下是查找关键路径的程序。\n"); TopologicalOrder(G,T); CriticalPath(G); return 0; }
  • 关键路径

    千次阅读 2016-11-23 21:00:40
    关键路径

    今天学习了图的关键路径,来说一说我的心得体会,分享出来,希望帮助到大家。

     在学习之前,我们要先了解一下什么是关键路径,与关键路径相关的知识点是什么。

     关键路径:若有向图中,诸顶点表示事件,诸有向边表示活动持续事件,则该图为活动边网络,简称AOE网。AOE网中的关键路径,就是完成整个网络所需的最短时间,亦最长路径,AOE网中,往往有若干项活动可以平行的进行,因此,从开始顶点到最后一个顶点的最长路径称为关键路径。

     知识点:1.某事件的最早发生时间:从开始事件到此事件的最长路径,ee表示。比如:ee(E)=max( AB+BE,  AC+CE)=7.只有E事件最早发生时间大于ee(E),才能保证一定完成B,C事件。否则,无法保证。

    2.某事件允许的最晚发生时间:比如,el(E)=18-11=7;18为A到I的最长路径,11为E到I的最长路径,这是说保证总的最短时间在18 ,E发生的最早时间是11的情况下,E可以提早,也可以晚会,但最晚是7。

    3.缓冲时间,以C为例,最早发生时间是4,允许的最晚发生时间=18-12=6.18为A到I的最长路径,12为C到I的最长路径,6-4=2.说明,C事件可以延时2,这就是缓冲时间。

    下边看图:

     

    缓冲时间等于0时,我们叫他关键活动,比如E,ee(E)=7,el(E)=18-11=7,ee(E)=el(E),关键活动连接起来就是关键路径。

    现在我们得到图的邻接矩阵:

    们需要求得就是每个顶点事件的最早发生时间,即最长路径,我们可以通过前一个顶点事件的最长路径加上当前的边的权就是当前事件的最长路径。用,0,1,2,3,。。。分别代表A,B,C,D,,,I

         

      那么我们怎么知道当前事件的前一个顶点事件是否存在呢,通过矩阵,如果不为0,即存在。

    通过g->matrix[j][i]+a[j]>max得到,前一个顶点事件的最长路径加上当前的边的权就是当前事件的最长路径。

    	int i,j;
    	int a[MAX]={0},b[MAX]={-10},c[MAX]={0};
    	int max=0;//最长路径
    	for( i=0;i<g->vexnum;i++) //列数遍历
    	{
    		for( j=0;j<g->vexnum;j++)//行数遍历
    		{
    
    			if(g->matrix[j][i]>0 && g->matrix[j][i]+a[j]>max) //如果g->matrix[j][i]大于0,说明此顶点有前顶点,由前边的遍历可知,前顶点的最长路径a[j],
    															  //加上g->matrix[j][i]的路径就是当前a[i]的路径
    			{
    				max=g->matrix[j][i]+a[j];
    				a[i]=max;
    			}
    		}
    		max=0;
    	}
    求出第一个顶点到每一个顶点的最长路径后,我们要求出每一个顶点事件到终点的发生时间。把矩阵转个向即可得出:


      这是代码:

    	for( i=g->vexnum-1;i>=0;i--) //列数遍历
    		{
    			for( j=g->vexnum-1;j>=0;j--)//行数遍历
    			{
    
    				if(g->matrix[i][j]>0 && g->matrix[i][j]+b[j]>max) //如果g->matrix[j][i]大于0,说明此顶点有前顶点,由前边的遍历可知,前顶点的最长路径a[j],
    																  //加上g->matrix[j][i]的路径就是当前a[i]的路径
    				{
    					max=g->matrix[i][j]+b[j];
    					b[i]=max;
    				}
    			}
    			max=0;
    		}
    最后,相比较就行了。

            源代码:

    #include<stdio.h>
    #include<stdlib.h>
    #include <malloc.h>
    #include <string.h>
    #define MAX 20
    #define INF 100      // 此处修改最大值
    #define nLENGTH(a)  (sizeof(a)/sizeof(a[0]))
    #define eLENGTH(a) ( sizeof(a) / sizeof(char) )/ ( sizeof(a[0]) / sizeof(char) )
    typedef struct _graph
    {
        char vexs[MAX];       // 顶点集合
        int vexnum;           // 顶点数
        int edgnum;           // 边数
        int matrix[MAX][MAX]; // 邻接矩阵
    }Graph, *PGraph;
    // 边的结构体 
    typedef struct _EdgeData
    {
        char start; // 边的起点
        char end;   // 边的终点
        int weight; // 边的权重
    }EData;
    //指向节点的位置
    int point_node(PGraph g,char c)
    {
    	for(int i=0;i<g->vexnum;i++)
    	{
    		if(g->vexs[i]==c)
    		{
    			return i;
    		}
    	}
    	return -1;
    }
    PGraph create_graph(int b[][3],char a[],int n,int e)
    {
    	char c1,c2; //边的2个顶点
    	PGraph g; //矩阵
    	g=(PGraph)malloc(sizeof(Graph));
    	//memset()第一个参数 是地址,第二个参数是开辟空间的初始值,第三个参数是开辟空间的大小
    	memset(g, 0, sizeof(Graph));
    	printf("顶点个数:\n");//顶点数
    	g->vexnum=n;
    	printf("%d\n",g->vexnum);
    	printf("边个数:\n");//边数
    	g->edgnum=e;
    	printf("%d\n",g->edgnum);
    	//初始化顶点
    	for(int j=0;j<g->vexnum;j++)
    	{
    		g->vexs[j]=a[j];
    	}
    	for(int i=0;i<g->edgnum;i++)
    	{
    		int p1,p2;
    		c1=char(b[i][0]);
    		c2=char(b[i][1]);
    		p1=point_node(g, c1);
    		p2=point_node(g, c2);
    		if (p1==-1 || p2==-1)
            {
                printf("input error: invalid edge!\n");
                free(g);
                continue;
            }
    		g->matrix[p1][p2]=b[i][2];
    		
    	}
    	return g;
    }
    
    //关键路径的最短时间
    //关键路径法(Critical Path Method,CPM)
    void CPM_road(PGraph g)
    {
    	int i,j;
    	int a[MAX]={0},b[MAX]={-10},c[MAX]={0};
    	int max=0;//最长路径
    	for( i=0;i<g->vexnum;i++) //列数遍历
    	{
    		for( j=0;j<g->vexnum;j++)//行数遍历
    		{
    
    			if(g->matrix[j][i]>0 && g->matrix[j][i]+a[j]>max) //如果g->matrix[j][i]大于0,说明此顶点有前顶点,由前边的遍历可知,前顶点的最长路径a[j],
    															  //加上g->matrix[j][i]的路径就是当前a[i]的路径
    			{
    				max=g->matrix[j][i]+a[j];
    				a[i]=max;
    			}
    		}
    		max=0;
    	}
    	//显示最长路径
    	printf("第一个顶点到每一个顶点的最长路径:");
    	printf("\n");
    	for(i=0;i<g->vexnum;i++) 
    	{
    		printf("%d\t",i);
    	}
    	printf("\n");
    	for(i=0;i<g->vexnum;i++) 
    	{
    		printf("%d\t",a[i]);
    	}
    	printf("\n");
    	printf("最后一个顶点到每个顶点的最长路径:");
    		for( i=g->vexnum-1;i>=0;i--) //列数遍历
    		{
    			for( j=g->vexnum-1;j>=0;j--)//行数遍历
    			{
    
    				if(g->matrix[i][j]>0 && g->matrix[i][j]+b[j]>max) //如果g->matrix[j][i]大于0,说明此顶点有前顶点,由前边的遍历可知,前顶点的最长路径a[j],
    																  //加上g->matrix[j][i]的路径就是当前a[i]的路径
    				{
    					max=g->matrix[i][j]+b[j];
    					b[i]=max;
    				}
    			}
    			max=0;
    		}
    
    	//显示最长路径
    	printf("\n");
    	for(i=0;i<g->vexnum;i++) 
    	{
    		printf("%d\t",i);
    	}
    	printf("\n");
    	for(i=0;i<g->vexnum;i++) 
    	{
    		printf("%d\t",b[i]);
    	}
    	printf("\n");
    	for(i=0;i<g->vexnum;i++)
    	{
    		if(a[i]==a[g->vexnum-1]-b[i])
    		{
    				printf("%c\t",g->vexs[i]);
    		}
    	}
    
    
    
    }
    
    
    
    
    //测试
    int main()
    {
    	int i,j;
    	PGraph gp;
    	//测试用例
    
    
    	char a[]={'A', 'B', 'C', 'D', 'E', 'F', 'G','H','I'};
    	int b[][3]={
            {'A', 'B',6}, 
            {'A', 'C',4}, 
            {'A', 'D',5}, 
            {'B', 'E',1}, 
            {'C', 'E',1}, 
            {'D', 'F',2}, 
            {'E', 'G',9},
    		{'E', 'H',7},
    		{'F', 'H',4},
    		{'G', 'I',2},
    		{'H', 'I',4}}; 
    
    	//测试用例
    
    	int n=nLENGTH(a);
    	int e=eLENGTH(b);
    	gp=create_graph(b,a,n,e);
    
    	//打印矩阵
    	for (i = 0; i < gp->vexnum; i++)
        {
            for (j = 0; j < gp->vexnum; j++)
                printf("%d  ", gp->matrix[j][i]);
            printf("\n");
        }
    	printf("\n");
    	CPM_road(gp);
    	return 0;
    
    }







    展开全文
  • 求关键路径

    千次阅读 2015-03-30 10:37:52
    求关键路径 1、重要概念  (1)AOE (Activity On Edges)网络 如果在无有向环的带权有向中用有向边表示一个工程中的各项活动(Activity),用边上的权值表示活动的持续时间(Duration),用顶点表示事件...

    求关键路径

    1、重要概念

               1AOE (Activity On Edges)网络 如果在无有向环的带权有向图中用有向边表示一个工程中的各项活动(Activity),用边上的权值表示活动的持续时间(Duration),用顶点表示事件(Event)则这样的有向图叫做用边表示活动的网络,简称AOE (Activity On Edges)网络。AOE网是一个带权的有向无环图。

    AOE网络在某些工程估算方面非常有用。例如,可以使人们了解:

        a、完成整个工程至少需要多少时间(假设网络中没有环)?

         b、为缩短完成工程所需的时间应当加快哪些活动

         (2关键路径(Critical Path) AOE网络中有些活动顺序进行,有些活动并行进行。从源点到各个顶点,以至从源点到汇点的有向路径可能不止一条。这些路径的长度也可能不同。完成不同路径的活动所需的时间虽然不同,但只有各条路径上所有活动都完成了,整个工程才算完成因此,完成整个工程所需的时间取决于从源点到汇点的最长路径长度,即在这条路径上所有活动的持续时间之和。这条路径长度最长的路径就叫做关键路径(Critical Path)

          如果一个活动的最早开始时间等于它的最迟开始时间,那么这个活动就被称为是关键活动,关键活动连接在一起就是关键路径。

    如图1就是一个AOE网,该网中有11个活动和9个事件。每个事件表示在它之前的活动已经完成,在它之后的活动可以开始。如事件v5表示a4a5活动已经完成,a7a8活动可以开始。每个弧上的权值表示完成相应活动所需要的时间,如完成活动a1需要6天,a8需要7天。

    14、求关键路径 - 墨涵 - 墨涵天地

    1

           AOE网常用于表示工程的计划或进度。由于实际工程只有一个开始点和一个结束点,因此AOE网存在唯一的入度为0的开始点(又称源点)和唯一的出度为0的结束点(又称汇点),例如图1AOE网从事件v1开始,以事件v9束。同时AOE网应当是无环的。

    3)算法描述中要用到的几个表达

    e(i)表示活动ai的最早开始时间,l(i)表示活动ai的最迟开始时间; l(i)-e(i)表示完成活动的时间余量。事件vi 的最早开始时间表示为ve(i), 事件vi 的最迟允许开始时间vl(i)

    l[k] = e[k]的活动就是关键活动。为求得e[k]l[k],需要先求得从源点v0到各个顶点vi  ve[i]  vl[i]。如果活动a由弧<j,k>表示,其持续时间记为dut(<j,k>),则有如下关系:          
            e(i)=ve(j)
            l[i] = vl[k] – dut(<i, k>)

    ve(j)vl(j)需分两步进行:

    1

    14、求关键路径 - 墨涵 - 墨涵天地

    其中, T是所有以第j个顶点为头的弧的集合。

    2

    14、求关键路径 - 墨涵 - 墨涵天地

    其中, S是所有以第i个顶点为尾的集合。

    这两个递推公式的计算必须分别在拓扑有序及逆拓扑有序的前提下进行。也就是说,ve(j-1)必须在v的所在前驱的最早发生时间求得之后才能确定,而vl(j-1)则必须在v的所有后继的最迟发生时间求得之后才能确定。因此,可以在拓扑排序的基础上计算ve(j-1)vl(j-1)

    2、需要说明的地方

    1)上面的图1中的关键路径就为

    14、求关键路径 - 墨涵 - 墨涵天地

    2)影响关键活动的因素是多方面的,任何一项活动持续时间的改变都会影响关键路径的改变。关键活动的速度提高是有限度的,只有在不改变网的关键路径的情况下,提高关键活动的速度才有效。如果网中有几条关键路径,那么单是提高一条关键路径上的关键活动的速度,还不能导致整个工程缩短工期,而必须同时提高几条关键路径上的活动的速度。


    更通俗地来理解:

     
    在这种AOE网中,最长的一条路径就是关键路径,因为图中每个活动都是必须的,只有最长的工期完成后,项目才真正完成了,图中10+9+20+10 也就是ADFHJ  ,显然是最长的,所以为关键路径

    从左边开始每个活动所需要最长的时间就是最早开始时间,如C,只有A指向它,那么最早开始时间就是5;F,A->C->F
    5+4=9,A->D->F 10+9=19,两者比较,后者大,故19为最早开始时间,依次类推。

    从右边倒推,可以求的最迟开始时间,如J为49,以I为例,I->J 倒推 49-4=45 所以I最迟开始时间为45;H为例,H->J 倒推49-10=39,H->I->J 倒推 49-4-1=44,两者取最小的,所以H的最迟开始时间为39。

    展开全文
  • AOE求关键路径

    千次阅读 2019-12-03 18:26:20
    在AOE,一个事件发生的要求是通向其的活动全部结束,那么这么时间发生的最早时间就是与之相连的所有活动全部结束后的时间,而关键路径就是,使得事件都发生的路径。这个路径的时间一定是最长的。 基本思想 1.可以...

    AOE

    AOE图就是将节点作为事件,而中间的弧作为活动,权是活动持续的时间。

    关键路径

    在AOE图,一个事件发生的要求是通向其的活动全部结束,那么这么时间发生的最早时间就是与之相连的所有活动全部结束后的时间,而关键路径就是,使得事件都发生的路径。这个路径的时间一定是最长的。

    基本思想

    1.可以利用邻接矩阵的方式存储元素之间是否相连
    2.在使用一个数组记录节点的入度
    3.一个记录每个节点关键路径的字符串数组
    首先判断入读和和出度为零的节点,分别记为tail,head。
    将tail入队,然后,遍历以队首元素为tail的弧,若是不为无穷或则0,就将head的入度减一,知道入度为0就入队,直到队为空就结束。

    实现代码

     while(!all.empty())    //all为队列
        {
            int j=all.front();
            all.pop();
            for(int i=1;i<=a;i++)
            {
                if(p[j][i]!=9999)
                {
                    if(v[j]+p[j][i]>v[i])
                    {v[i]=v[j]+p[j][i];
                      path[i]=path[j];
                      path[i].push_back(48+j);
                    }
                      l[i]--;
                      if(l[i]==0)
                      {
                          all.push(i);    //入队就说明所有通过他的路径都以遍历结束,并且选出最长路径
                      }
                }
            }
        }
    
    展开全文
  • 关键路径

    千次阅读 多人点赞 2017-02-28 10:41:47
    关键路径
  • AOE网、关键路径
  • 有向关键路径(C++代码)

    千次阅读 2017-03-29 21:31:51
    //寻找关键路径 #include #include #include #include #include using namespace std; //最大边数,最大点数 const int Max_M=100100; const int Max_N=50100; struct Graph { int nod
  • 关键路径

    千次阅读 2012-12-29 17:36:59
    摘 要 介绍关键路经的算法,对于给出的事件结点网络,要求出从起点到终点的所有路径,经分析、比较后找出长读最大的路径,从而得出求关键路径的算法,并给出计算机上机实现的源程序。 关键词 关键路径 最少时间...
  • AOE关键路径的求解

    千次阅读 2019-10-24 00:02:21
    AOE网和关键路径 本文算是相对知识密度较大的文章,建议看的时候仔细一点,并在迷惑的地方搜索其他文章。 文章目录AOE网和关键路径AOE网和AOV网一些概念关键路径关键路径相关量工程规划工程规划 AOE网和AOV网 ...
  • -关键路径

    千次阅读 2018-10-13 18:51:49
    关键路径(长度最长的路径)决定工期 关键活动:工程正常开展最早开始时间等最迟开始时间的活动。 输入:创建。 输出:所有活动及其权值、最早开始时间、最晚开始时间以及是否为关键活动 。是的话为Yes,反之为...
  • AOE网求关键路径

    千次阅读 2014-08-05 11:23:06
    下表给出了某工程各工序之间的优先关系和各工序所需的时问(其中“一”表示无先驱工序),请完成...(3) 关键路径并指明完成该工程所需的最短时间。 工序代号 A B C D
  • -关键路径算法

    2020-08-17 13:49:08
    关键路径(CriticalPath) 我们把路径上各个活动所持续时间之和称为路径长度,从源点到汇点具有最大长度的路径叫关键路径,在关键路径上的活动叫做关键活动.。 AOV网和AOE网 算法用到的4个关键变量: **etv ...
  • 目录 0.——判环 0.1.1无向判断是否存在环 0.1.2有向判断是否存在环 0.2无向判环 0.3有向判环 ...1.有向的拓扑排序 ...2.关键路径 ...求关键路径的完整代码与测试用例: 无向、有向判环...
  • 数据结构之关键路径

    千次阅读 2018-11-06 11:18:43
    title: 数据结构之关键路径 tags: 数据结构与算法之美 一、AOE和AOV网 1.AOE网 AOE-网:指用边表示活动的网,是一个带权的有向无环,其中,顶点表示事件弧表示活动,权表示活动持续的时间,通常一个AOE-网可...
  • 有向无环关键路径

    千次阅读 2018-01-28 21:48:52
    **有向无环关键路径** 1 AOE-网:边表示活动的网。AOE-网是一个带权的有向无环,其中顶点表示事件,弧表示活动,权表示活动持续的时间。 2 通常AOE-网可用来估算工程的完成时间。 例图: 该...
  • DAG中的关键路径算法

    千次阅读 2013-11-26 22:38:53
    什么是DAG中的关键路径?简单的将就是不可以推辞的活动组成的路径,这对于工程上有着极其重要的应用,利用关键路径算法可以计算那些事件是不可推辞的,必须如期完成,下面是代码: //关键路径算法 //的邻接矩阵...
  • 关键路径的计算

    千次阅读 多人点赞 2014-06-21 09:46:46
    从源点到汇点路径长度最长的路径为该工程的关键路径,即关键路径可以保证所有路径的活动都能够完成。 ok,再次进入我们的作业题: ... 2)哪些是关键活动,在中表示出关键路径 我们先计算最早发生时...
  • 题目如下:事件最早发生事件法:找从原点到该事件的最长路径(从前往后推) 对a:Ve=0 对b:Ve=max{ 2 , 15+4 }=19 对c:Ve=15 对d:Ve=19+10=29 对e: Ve=max{ 19+19,15=17 }=38 对f:Ve=38+5=43事件最...
  • AOE网上的关键路径 Time Limit: 1000MS Memory limit: 65536K 题目描述  一个无环的有向称为无环(Directed Acyclic Graph),简称DAG。  AOE(Activity On Edge)网:顾名思义,用边表示活动...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 42,154
精华内容 16,861
关键字:

关键路径图怎么求