最短工期 数据结构实现

最短工期(20 分)

一个项目由若干个任务组成,任务之间有先后依赖顺序。项目经理需要设置一系列里程碑,在每个里程碑节点处检查任务的完成情况,并启动后续的任务。现给定一个项目中各个任务之间的关系,请你计算出这个项目的最早完工时间。

输入格式:

首先第一行给出两个正整数:项目里程碑的数量 N100)和任务总数 M。这里的里程碑从 0 到 N1 编号。随后 M 行,每行给出一项任务的描述,格式为“任务起始里程碑 任务结束里程碑 工作时长”,三个数字均为非负整数,以空格分隔。

输出格式:

如果整个项目的安排是合理可行的,在一行中输出最早完工时间;否则输出"Impossible"。

输入样例 1:

9 12
0 1 6
0 2 4
0 3 5
1 4 1
2 4 1
3 5 2
5 4 0
4 6 9
4 7 7
5 7 4
6 8 2
7 8 4

输出样例 1:

18

输入样例 2:

4 5
0 1 1
0 2 2
2 1 3
1 3 4
3 2 5

输出样例 2:

Impossible
作者: 陈越
单位: 浙江大学
时间限制: 400ms
内存限制: 64MB
代码长度限制: 16KB

编译器
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MaxVertexNum 100   /* 最大定点数设为100 */ 
typedef int Vertex;        /* 用顶点下标表示顶点,为整形 */ 
typedef int WeightType;    /* 边的权值设为整形 */ 
typedef char DataType;     /* 顶点储存的数据类型设为字符型 */ 
int time[MaxVertexNum]={0};

/* 队列的相关操作 */ 
/* 队列的顺序储存实现结构定义 */ 
typedef int ElementType;
typedef int Position;
typedef struct QNode *PtrToQNode;
struct QNode{
	ElementType *Data;    /* 储存元素的数组 */ 
	Position Front, Rear; /* 队列的头尾指针 */ 
    int MaxSize;          /* 队列的最大容量 */ 
};
typedef PtrToQNode Queue;
/* 队列的创建 */
Queue CreatQueue(int MaxSize)
{
	Queue Q = (Queue)malloc(sizeof(struct QNode));
    Q->Data = (ElementType *)malloc(MaxSize*sizeof(ElementType));
    Q->Front = Q->Rear=0;
    Q->MaxSize = MaxSize;
    
    return Q;
}
int IsFull(Queue Q)
{
	if((Q->Rear+1)%Q->MaxSize==Q->Front)
		return 1;
	else
		return 0;
}
void AddQ(Queue Q, ElementType X)  /* 入队列 */ 
{
	if(IsFull(Q)){
		printf("队列满");
	}
	else{
		Q->Rear = (Q->Rear+1)%Q->MaxSize;
		Q->Data[Q->Rear] = X;
	}
}
int IsEmpty(Queue Q)  /* 判断队列是否为空 */ 
{
	if(Q->Front==Q->Rear)
		return 1;
	else
		return 0;
}
ElementType DeleteQ(Queue Q)  /* 出队列 */ 
{
	if(IsEmpty(Q)) {
		printf("队列空");
	}
	else  {
		Q->Front = (Q->Front+1)%Q->MaxSize;
		return Q->Data[Q->Front];
	}
} 


/* 边的定义 */
typedef struct ENode *PtrToENode;
struct ENode{
	Vertex V1, V2;		/* 有向边<V1, V2> */ 
	WeightType Weight;  /* 权重 */ 
};
typedef PtrToENode Edge;

/* 邻结点的定义 */ 
typedef struct AdjVNode *PtrToAdjVNode;
struct AdjVNode{
	Vertex AdjV;	/* 邻接点下标 */
	WeightType Weight;  /* 边权重 */ 
	PtrToAdjVNode Next;
};

/* 顶点表头节点的定义 */ 
typedef struct Vnode{
	PtrToAdjVNode FirstEdge; /* 边表头指针 */  
	//DataType Data;
}AdjList[MaxVertexNum];  /* AdjList 是邻接表的类型 */ 

/* 图节点的定义 */
typedef struct GNode *ProToGNode;
struct GNode{
	int Nv;  /* 顶点数 */
	int Ne;  /* 边数 */
	AdjList G;  /* 邻接表 */ 
};
typedef ProToGNode LGraph;

int TopOrder[MaxVertexNum];
LGraph CreateGraph(int VertexNum) /* 初始化一个有N个顶点但是没有边的图  */ 
{ 
	Vertex V;
	LGraph Graph;
	
	Graph=(LGraph)malloc(sizeof(struct GNode));  /* 建立图 */
	Graph->Nv=VertexNum;
	Graph->Ne=0;
	/* 初始化邻接表头指针 */ 
	for( V = 0; V < Graph->Nv; V++)
		Graph->G[V].FirstEdge=NULL; 
	
	return Graph;
}
void InsertEdge(LGraph Graph, Edge E)   //插入边 
{
	PtrToAdjVNode NewNode;
	/*插入边 <v1, v2>*/
	/* 为V2建立新的邻接点 */
    NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
	NewNode->AdjV = E->V2;
	NewNode->Weight = E->Weight; 
	/* 将V2插入V1的表头 */
	NewNode->Next=Graph->G[E->V1].FirstEdge;
	Graph->G[E->V1].FirstEdge=NewNode;
	/* 若是无向图还要插入边 */
	/*为V1建立新的邻接点 */
	//省略这一步 
}
LGraph BuildGraph()
{
	LGraph Graph;
	Edge E;
	Vertex V;
	int Nv, i;
	scanf("%d", &Nv);  /* 读入顶点数 */ 
	Graph = CreateGraph(Nv); /* 初始化一个有Nv个顶点但是没有边的图  */ 
	
	scanf("%d", &(Graph->Ne));  /* 读入边数 */ 
	if(Graph->Ne != 0) {/* 如果有边 */ 
		E=(Edge)malloc(sizeof(struct ENode)); /* 建立边结点 */
		/* 读入边,格式为 "起点 终点 权重” */
		for(i=0; i<Graph->Ne; i++){
			scanf("%d %d %d",&E->V1,&E->V2,&E->Weight);
			/* 注意如果weight不是整形 weight的输入格式要更改*/
			InsertEdge(Graph, E); 
		}
	}
	/* 如果顶点有数据的话,读入顶点数据 */ 
	/*
	  for(V = 0; V < Graph->Nv; V++)
	    scanf("%c",&(Graph->G[V].Data));
	*/
	return Graph;
}
int TopSort(LGraph Graph) /*拓扑排序*/
{
	/* Indegree计算顶各个顶点的入度 */ 
	int Indegree[MaxVertexNum], cnt;
	Vertex V;
	PtrToAdjVNode W;
	Queue Q = CreatQueue(Graph->Nv);
	/* 初始化Indegree[] */
	for( V = 0; V<Graph->Nv; V++)
		Indegree[V]=0;
	/* 遍历图,得到Indegree[] */
	for( V = 0; V<Graph->Nv; V++)
		for(W = Graph->G[V].FirstEdge; W; W = W->Next)
			Indegree[W->AdjV]++;   //入度增加 
	/* 将所有入度为零的顶点入队列 */
	for(V = 0;V < Graph->Nv; V++)
		if(Indegree[V]==0)
			AddQ(Q, V);
	cnt = 0;  
	while(!IsEmpty(Q)){
		V = DeleteQ(Q);  /* 弹出一个入度为零的顶点 */
		//printf("%d\n",V);
		
		/* 求最短工期 */
		for(W=Graph->G[V].FirstEdge; W!=NULL; W = W->Next)
		{
			if(time[W->AdjV]<time[V]+W->Weight)
				time[W->AdjV]=time[V]+W->Weight;
		}
		
		TopOrder[cnt++] = V; /* 将之存为结果序列的下一个元素 */ 
		for(W=Graph->G[V].FirstEdge; W!=NULL; W = W->Next)
		{
		  if(--Indegree[W->AdjV]==0)  //若删除V使得W-Adiv入度为零 
		  	AddQ(Q, W->AdjV);   //则此顶点入队列 
		}
	}
	if(cnt != Graph->Nv)
	  return  -1;
	else 
	  return   1; 
}
int main()
{
	int N;
	LGraph Graph;
    Graph=BuildGraph();  /* 建立一个邻接表,并读入全部数据到表中 */ 
    /* 之后进行拓扑排序 */ 
    N=TopSort(Graph); /* 拓扑排序 */
	if(N==1)
	{
		int Max=time[0];
		for(int i=1;i<Graph->Nv;i++)
		{
			if(time[i]>Max)
				Max=time[i]; 
		}
		printf("%d",Max);
	}
	else
	  printf("Impossible");
	return 0;	
}

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值