利用工程活动图 AOE 网设计一个算法
题目
★★ 已知假想的工程活动图 AOE 网,试设计一个算法,要求:
判断工程是否可行;
- 求出工程中每个活动的最早开始时间 e(i),最迟开始时间 l(i)和全工程可以完成的最早时间;
- 确定工程中关键路径和可使整个工程的工期缩短的关键活动。
说明: 可以给出一个假想的工程活动图 AOE 网,如下图所示(仅为示例),也可以给出工程的活动情况,画出 AOE 网。
软件功能
本软件有如下功能:
用户可以点击“开始创建”自行建立 AOE 工程网络,鼠标点击创建面板生成一个事件,依次有序点击两个事件可以创建活动,创建的活动上会显示活动的权重。AOE 活动网络建成之后,点击“执行计算”,程序自动完成关键路径的计算,若构建的网络不满足条件,比如有多个源点、汇点、环路,或者事件已经创建,程序均会进行相应报错。当完成关键路径的计算后,会在创建面板以红色加粗显示关键路径,并且在左侧活动信息面板详细显示各个活动的信息,关键活动路径同样给予突出显示,在程序窗口右下角,会给出整个工程最早的完成时间,即关键路径活动时间之和。用户可以重复创建和计算关键路径的过程。
用到的主要控件是 panel 面板和 tableLayoutPanel 面板,用于在程序内 GroupBox 划分空间的基础上划分面板,事件的生成是生成一个按钮,连线的生成通过调用System.Drawing.Drawing2D 的画图功能,活动信息的展现是增添表格。关键路径的计算采用的是课本上的计算方法,在此之间需要先进行 AOV 的拓扑排序,确定没有环路方可继续程序运行。
设计思想
本软件仍然是利用 C#的.Net Framework 来写的图形界面。主要目的是能够生成或者创建一个 AOE 活动网络,并对这个网络进行求解关键路径。在 C++ 里用指针表示的邻接表很容易实现活动网络图结构的存储,然而 C#虽然构建图形界面比较方便,但是由于没有指针这一特性,很多方面会受到限制,只能用静态的数组来模拟指针构建邻接链表。主要采用三个类来表示 AOE 活动网络:活动类、事件类和 AOE 网络结构类,活动类包括活动的始终,活动的权重,活动的最早和最晚开始时间以及活动的起点终点坐标;事件类包含以该事件为起点的所有的活动的变长数组,相当于邻接表的某一行;AOE 网络类中包含各种求解过程中要用到的方法。难点在于打破 C++ 的指针思维方式,以变长数组构建邻接表。
主要算法思想:
求活动最早开始时间:活动出发顶点(时间)的最早开始时间
求活动的最晚开始时间:从要求最晚截止时间开始,反向推导,最晚工程技术时间依次
减去路径上各活动的时间
求关键路径和关键活:根据各顶点的 ve 和 vl 值,求每个活动的最早开始时间 e(s)和最迟开始时间 l(s),若某条弧(活动)满足条件 e(s)=l(s),则该活动为关键活动,关键活动连接起来就是关键路径。值得注意的是:关键路径可能有多条。
容错性考虑:
判断工程中是否创建事件和活动遍历所有事件节点,检查以该节点开始的活动的可变长数组是否是空的,相当于检查邻接表是否为空,若是空的,则工程中不存在活动,需要重新创建。
检查工程中是否有多个源点:
遍历所有事件节点,统计所有入度为 0 的节点的数量总和,如果数量大于 1,则说明不止一个源点,工程不符合条件,不能求解。
检查工程中是否有多个汇点:
遍历所有事件节点,统计以该事件节点开始的活动的可变长数组为空的事件个数,如果统计出的个数大于 1,则说明有多个事件为截止事件,工程中存在多个汇点,无法求解关键活动。
检查工程中是否有环路:
AOE 活动网络中是不存在环路的,为检查活动网络中是否有环路,需要对所有事件节点进行拓扑排序,如果排序后的离散节点数与之前的节点数相同,则 AOE 活动网络中不存在环路,否则,需要重新创建工程。
逻辑结构与物理结构
程序主要构成:
Activity 类: public class Activity
{ public int start;
// 活动起始事件序号
public int end;
// 活动结束事件序号
public int weight;
// 活动持续时间,权重
public int e;
// 活动最早开始时间
public int l;
// 活动最迟开始时间
public bool critical;
// 是否为关键活动
public Point p_start = new Point();
// 活动起点坐标(画图用)
public Point p_end = new Point(); // 活动终点坐标(画图用)
}
Event 类:
public class Event
{
public bool critical;
// 是否为关键路径上的事件
public List<Activity> next = new List<Activity>(); // 以该事件为开始的
活动
public int ins;
// 入度
public int e;
// 事件最早发生时间
public int l;
// 事件最迟发生时间
}
NetWork 类:
public class Network
{
Graphics g;
public List<Event> net = new List<Event>();
// AOE网邻接表
public int start;
// 工程起始事件序号
public int end;
// 工程结束事件序号
List<int> topology = new List<int>();
// 拓扑排序结果
}
主要的数据结构是 List形式的动态变长数组,该数组在计算机中占据连续的内存,属于物理结构。
程序计算的主要方法(函数)
private void button1_Click(object sender, EventArgs e)
//开始创建
private void panel1_MouseClick(object sender, MouseEventArgs e)
//画AOE网络
private void eventClick(object sender, MouseEventArgs e)
//点击事件
private void button2_Click(object sender, EventArgs e)
//执行计算
protected override void OnPaint(PaintEventArgs e)
//重新设置控件的形状,绘制圆形
按钮
public String Is_Able_Continue()
// 求解工程是否可行,可继续
public void eventsTime()
// 求各事件的最早和最迟开始时间
public void activitiesTime(AOE main)
// 求各活动的最早和最迟开始时间
开发平台
CPU:AMD Ryzen 7 4800H with Radeon Graphics 2.90GHz
系统类型:Windows10 64 位,基于 X64
开发环境:Visual Studio 2019 professional
Visual C#
.Net Framework
调用的系统命名空间:
using System;using System.Collections.Generic;using System.Drawing;using System.Drawing.Drawing2D;using System.Windows.Forms;
系统的运行结果分析说明
利用 Visual Studio C# .Net Framework 集成开发环境,先设计好整体页面,将各组件布置到位,主要部件为 panel 控件和 tabelLayoutPanel 控件,主要调用的绘图函数为System.Drawing.Drawing2D 下的 DrawLine(pen, start, end)。题目要求算出 AOE 工程网络中的关键路径。本软件已达到基本要求,并且可以自己灵活创建 AOE 网络,网络中标出活动标号,和活动权重,当计算完毕后,会对关键路径加粗加红显示,关键活动的信息也会加红显示。经过验证,正确性良好,稳定性良好,已经充分考虑各种错误情况并且给予相应的处理,容错能力良好。并且给予相应的提示,比较人性化。
操作说明
程序初始界面:
点击“开始创建”按钮,开始创建工程
创建活动
鼠标在面板上点击,生成事件
鼠标依次按照顺序点击活动上的两个事件,开始创建活动
创建完活动,点击“执行计算”
计算前
计算后:关键路径加粗加红显示
活动信息:关键活动加红突出显示
显示工程最早完成时间:
错误提示