数据结构PTA习题:基础实验6-2.6 最短工期 (25分)——拓扑排序、关键路径

基础实验6-2.6 最短工期 (25分)

Given the relations of all the activities of a project, you are supposed to find the earliest completion time of the project.
一个项目由若干个任务组成,任务之间有先后依赖顺序。项目经理需要设置一系列里程碑,在每个里程碑节点处检查任务的完成情况,并启动后续的任务。现给定一个项目中各个任务之间的关系,请你计算出这个项目的最早完工时间。

Input Specification:
Each input file contains one test case. Each case starts with a line containing two positive integers N (≤100), the number of activity check points (hence it is assumed that the check points are numbered from 0 to N−1), and M, the number of activities. Then M lines follow, each gives the description of an activity. For the i-th activity, three non-negative numbers are given: S[i], E[i], and L[i], where S[i] is the index of the starting check point, E[i] of the ending check point, and L[i] the lasting time of the activity. The numbers in a line are separated by a space.
首先第一行给出两个正整数:项目里程碑的数量 N(≤100)和任务总数 M。这里的里程碑从 0 到 N−1 编号。随后 M 行,每行给出一项任务的描述,格式为“任务起始里程碑 任务结束里程碑 工作时长”,三个数字均为非负整数,以空格分隔。

Output Specification:
For each test case, if the scheduling is possible, print in a line its earliest completion time; or simply output “Impossible”.
如果整个项目的安排是合理可行的,在一行中输出最早完工时间;否则输出"Impossible"。

Sample Input 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

Sample Output 1:

18

Sample Input 2:

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

Sample Output 2:

Impossible

在这里插入图片描述
C语言实现:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct graph
{
	int Ne;
	int Nv;
	int * * M;
};
typedef struct graph * Graph;
struct que
{
	int front;
	int rear;
	int * s;
};
typedef struct que * Queue;
Queue CreateQ(int N);
void AddQ(Queue Q, int y);
int DeleteQ(Queue Q);
Graph CreateGraph(int N);
int main()
{
	int N, M;
	scanf("%d %d", &N, &M);
	int i, j;
	Graph G;
	G = CreateGraph(N);
	G->Ne = M;
	int v1, v2, w;
	for (i = 0; i < M; i++)
	{
		scanf("%d %d %d", &v1, &v2, &w);
		G->M[v1][v2] = w;
	}
	int * Indegree;//记录各顶点入度
	Indegree = (int *)malloc(N * sizeof(int));
	for (i = 0; i < N; i++)
	{
		Indegree[i] = 0;
	}
	for (i = 0; i < N; i++)//初始化
	{
		for (j = 0; j < N; j++)
		{
			if (G->M[j][i] != -1)
			{
				Indegree[i]++;
			}
		}
	}
	int V = 0;
	int * Earliest;//记录各顶点的最早完工时间
	Earliest = (int *)malloc(N * sizeof(int));
	Queue Q;
	Q = CreateQ(N);
	for (i = 0; i < N; i++)//初始化
	{
		Earliest[i] = -1;
	}
	for (i = 0; i < N; i++)
	{
		if (Indegree[i] == 0)//找起点
		{
			AddQ(Q, i); Earliest[i] = 0;
			for (j = 0; j < N; j++)//删除图中起点的出边
			{
				if (G->M[i][j] != -1)
				{
					Indegree[j]--;
				}
			}
		}
	}
	while (Q->front != Q->rear)
	{
		V = DeleteQ(Q);
		for (i = 0; i < N; i++)
		{
			for (j = 0; j < N; j++)
			{
				if (G->M[V][j] != -1)//更新顶点V的所有邻接点的最短完工时间,各个顶点取其所有最短完工时间中的最大值
				{
					if (Earliest[j] < Earliest[V] + G->M[V][j])
					{
						Earliest[j] = Earliest[V] + G->M[V][j];
					}
				}
			}
			if (Indegree[i] == 0 && G->M[V][i] != -1)//入度=0的顶点放入队列中,并删除图中该顶点的出边
			{
				AddQ(Q, i);
				for (j = 0; j < N; j++)
				{
					if (G->M[i][j] != -1 && Indegree[j] != 0)
					{
						Indegree[j]--;
					}
				}
			}
		}
	}
	for (i = 0; i < N; i++)//存在环路,则项目不合理
	{
		if (Earliest[i] == -1)
		{
			printf("Impossible");
			break;
		}
	}
	if (i == N)//项目合理,这里考虑到可能有多个终点,所以输出所有顶点的最短完工时间的最大值
	{
		int max = Earliest[0];
		for (i = 1; i < N; i++)
		{
			if (Earliest[i] > max)
			{
				max = Earliest[i];
			}
		}
		printf("%d", max);
	}
	return 0;
}
Graph CreateGraph(int N)
{
	int i, j;
	Graph G;
	G = (Graph)malloc(sizeof(struct graph));
	G->Ne = 0;
	G->Nv = N;
	G->M = (int * *)malloc(N * sizeof(int *));
	for (i = 0; i < N; i++)
	{
		G->M[i] = (int *)malloc(N * sizeof(int));
	}
	for (i = 0; i < N; i++)
	{
		for (j = 0; j < N; j++)
		{
			G->M[i][j] = -1;
		}
	}
	return G;
}
Queue CreateQ(int N)
{
	Queue Q;
	Q = (Queue)malloc(sizeof(struct que));
	Q->front = Q->rear = -1;
	Q->s = (int *)malloc(N * sizeof(int));
	return Q;
}
void AddQ(Queue Q, int y)
{
	Q->rear++;
	Q->s[Q->rear] = y;
}
int DeleteQ(Queue Q)
{
	Q->front++;
	return Q->s[Q->front];
}
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值