SERCOI工程组是一个讲究效率的工程小组。为了规划和管理的方便,他们将一个工程分为若干个项目,每个项目都可以独立进行。所有项目都工作完毕时,整个工程也就完成了。每个项目都需要一定的工作时间。工程最后总耗时是从第一个项目开始到最后一个项目结束的这段时间。
各个项目之间可能存在也可以不存在相互制约关系。如果有制约关系,则可能是以下四种之一(设两个项目分别为p和q):
(1)SAS p q (p Sart After q Start,项目p在项目q开始之后才能开始)
(2)FAS p q (p Finish After q Start,项目p在项目q开始之后才能结束)
(3)SAF p q (p Sart After q Start,项目p在项目q结束之后才能开始)
(4)FAF p q (p Finish After q Start,项目p在项目q结束之后才能结束)
如果没有制约关系,则可同时进行。
例如:SAF 1 3表示项目1必须在项目3完成后才能开始。若项目3工作时间为3,起始时刻为2,则项目1最早在时刻5才能开始。
作为SERCOI小组的项目负责人,请你根据各个项目的工作时间及先后关系,找出一种安排工程的方案,使整个工程尽可能快的完成。
输入:
输入文件的第一行为项目总数N(1≤N≤100),设项目的编号依次为1,2,…,N。下面N行依次为完成每个项目所需的工作时间(每个项目占一行)。这个时间为不超过100的正整数。
接下来若干行是一些项目间先后次序关系的列表,每行的格式为:
<先后次序关系符> <项目p编号> <项目q编号>
其中:<先后次序关系符>为SAS、FAS、SAF、FAF中的任意一个,“(”表示一个空格符。
整个文件以一个字母“#”表示结束(单独占一行)
输出:
若问题有解,则输出文件有N行,依次输出项目1到项目N的最早开始时间(设整个工程从0时刻开始)。每行的格式为:(项目编号 最早开始时间)。
若问题无解,则输出文只有一行,为一个正整数0。
输入输出示例1:
project .in
3
2
3
4
SAF 2 1
FAF 3 2
#
project .out
1 0
2 2
3 1
输入输出示例2:
project .in
3
1
1
1
SAF 2 1
SAF 3 2
SAF 1 3
#
project .out
0
思路:用求关键路径算法实现。
#include<stdio.h>#include<stdlib.h>
#include<iomanip.h>
#include <process.h>
typedef struct node//边表结点
{
int adjvex; //邻接点编号
int dut; //弧的信息
struct node *next; //下一条弧指针
}edgenode;
typedef struct //顶点表结点
{
int projectname;//顶点域
int id;//顶点的入度信息
edgenode *link; //边表头指针
}vexnode;
void CreateGraphic(vexnode* Graphicmap,int projectnumber,int activenumber)//创建图
{
int begin,end,duttem; //分别代表弧的前节点,尾节点,活动时间
edgenode *p;// 边表头指针
for(int i=0;i<projectnumber;i++)
{
Graphicmap[i].projectname=i;//顶点的命名按0,1,2,3......
Graphicmap[i].id =0;//顶点的信息的度数均赋为零
Graphicmap[i].link =NULL;
}
printf("\n");
printf("请输入某项目的信息,并请用整形数字表示(格式:弧头,弧尾,权值):\n");
printf("例如:输入1,2,4 即代表结点1与2之间的活动需要4个时间单位。\n");
printf("\n");
for(int k=0;k<activenumber;k++) //activenumber为活动的数目,即弧的条数
{
scanf("%d,%d,%d",&begin,&end,&duttem); //请输入第%d条的起点、终点和权值
p=(edgenode*)malloc(sizeof(edgenode));//临时分配存储空间
p->adjvex =end-1;//因为是从零开始记的,姑要减一,就是让终点插入到邻接表内
p->dut =duttem; //该弧的活动时间为duttem
Graphicmap[end-1].id ++; //入度加一
p->next =Graphicmap[begin-1].link ;
Graphicmap[begin-1].link =p;//让下一个节点作为下一插入节点的前驱节点
}
}
int SearchMapPath(vexnode* Graphicmap,int projectnumber,int activenumber
,int& totaltime) //求出最大路径,并打印出关键路径
{
int i,j,k,m=0;
int front=-1,rear=-1;
int* topologystack=(int*)malloc(projectnumber*sizeof(int));//用来保存拓扑排列
int* vl=(int*)malloc(projectnumber*sizeof(int));//用来表示在不推迟整个工程的前提下,VJ允许最迟发生的时间
int* ve=(int*)malloc(projectnumber*sizeof(int));//用来表示Vj最早发生时间
int* l=(int*)malloc(activenumber*sizeof(int));//用来表示活动Ai最迟完成开始时间
int* e=(int*)malloc(activenumber*sizeof(int));//表示活动最早开始时间
edgenode *p; //边表头的指针
totaltime=0; //存放整个工程的最短时间
for(i=0;i<projectnumber;i++) ve[i]=0;//先把每个工程的最早发生时间初始化为零
for(i=0;i<projectnumber;i++)
{
if(Graphicmap[i].id==0)
{
topologystack[++rear]=i;//让所有的头节点入队列
m++; //记录入队列的顶点个数
}
}
while(front!=rear)
{
front++; //出队列
j=topologystack[front]; //拓扑排序的节点依次出队列
m++; //记录入队列的节点个数
p=Graphicmap[j].link ; //指向顶点指向的下一个顶点
while(p)
{
k=p->adjvex ; // 邻接点编号
Graphicmap[k].id --;//让入度减一,相当于删除一个入度为零的前驱节点,和相关的弧
if(ve[j]+p->dut >ve[k])//将最长的路径赋给VE[K]
ve[k]=ve[j]+p->dut ;
if(Graphicmap[k].id ==0)//如果入度为零,则入队列
topologystack[++rear]=k;
p=p->next ; //指向下一个节点
}
}
if(m<projectnumber)//如果有环,则不能遍历每个节点
{
printf("\n本程序所建立的图有回路不可计算出关键路径!\n");
printf("将退出本程序!\n");
return 0;
}
totaltime=ve[projectnumber-1];//最短完成时间即为最后一个节点所累加的时间之和
for(i=0;i<projectnumber;i++)
vl[i]=totaltime;
for(i=projectnumber-2;i>=0;i--)// 用逆拓扑排序来求活动Ai最迟完成开始时间,即从最后一个节点减去最短的时间
{
j=topologystack[i];
p=Graphicmap[j].link ;
while(p)
{
k=p->adjvex ;
if((vl[k]-p->dut )<vl[j])
vl[j]=vl[k]-p->dut ;
p=p->next ;
}
}
i=0;
printf("\n");
printf("| 起点 | 终点 | 最早开始时间 | 最迟完成时间 | 差值 | 备注 \n");
for(j=0;j<projectnumber;j++)
{
p=Graphicmap[j].link;
while(p)
{
k=p->adjvex ;
e[++i]=ve[j];
l[i]=vl[k]-p->dut;
printf("| %4d | %4d | %11d | %11d | %3d |",Graphicmap[j].projectname +1,Graphicmap[k].projectname +1,e[i],l[i],l[i]-e[i]);
if(l[i]==e[i]) //当差值为零时,则为关键路径
printf(" 关键活动 <%2d,%4d>",
Graphicmap[j].projectname +1,Graphicmap[k].projectname +1);
printf("\n");
p=p->next ;
}
}
return 1;
}
void seekkeyroot()//求关键路径的函数
{
int projectnumber,activenumber,totaltime=0;
printf("请输入这个项目的AOE-网的节点数: ");
scanf("%d",&projectnumber);
printf("请输入这个项目的AOE-网的活动个数: ");
scanf("%d",&activenumber);
vexnode* Graphicmap=(vexnode*)malloc(projectnumber*sizeof(vexnode));
CreateGraphic(Graphicmap,projectnumber,activenumber);//创建邻接图
SearchMapPath(Graphicmap,projectnumber,activenumber,totaltime);//求出最大路径,并打印出关键路径
printf("\n");
printf("整个工程所用的最短时间为:%d个单位时间\n",totaltime);
system("pause");
}
int main()
{
system("cls");
seekkeyroot();
}