(MOOC)08-图8 How Long Does It Take(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 N1), 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.

Output Specification:

For each test case, if the scheduling is possible, print in a line its earliest completion time; or simply output "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

这道题是结合了拓扑排序以及关键路径问题的题目,程序首先计算出图中每个顶点的出度和入度,出度为0的顶点就是重点,入度为0的点就是起点。每一次计算完入度为0的点的工期之后,都需要将与其相连的点的入度减1,相当于将这个入度为0的点从图中删掉了,然后再去计算下一个入度为0的点的最短工期,用到的公式是:Earliest[w]=max(Earliest[v]+v与w边的权重)。

入度放在Indegree[]的数组里面,每次寻找入度为0的点需要遍历一次数组,这样时间复杂度较高,大家可以尝试将入度为0的点入队列的方法,这样时间复杂度较低,由于我比较懒,就不用队列的方法了==。下面给出C++代码:

#include <iostream>
#define INFINITY 65535
using namespace std;

int Nv, Ne;
int Indegree[100] = { 0 };//入度初始化为0
int Outdegree[100] = { 0 };//出度初始化为0
int Earliest[100] = { 0 };//每个顶点最早的完成工期
int visit[100] = { 0 };//判断是否计算过这个顶点的计算工期了
int G[100][100];//建立图

void BuildGraph()//建立图
{
	int v1, v2,weight;
	for (int i = 0; i < Nv; i++)
		for (int j = 0; j < Nv; j++)
			G[i][j] = INFINITY;
	for (int i = 0; i < Ne; i++)
	{
		cin >> v1 >> v2 >> weight;
		G[v1][v2] = weight;
	}
}

int early(int w)                //求每一个顶点的最早完成时间
{
	int max=0;
	for (int i = 0; i < Nv; i++)
		if (G[i][w] != INFINITY)//判断哪些是入边
		{
			if (G[i][w] + Earliest[i]>max)
				max = G[i][w] + Earliest[i];
		}
	return max;
}

bool TopSort()
{
	int v=0,cnt=0;
	for (int i = 0; i < Nv; i++)//计算图中各个顶点的出度及入度
		for (int j = 0; j < Nv; j++)
			if (G[i][j] != INFINITY)
			{
				Indegree[j]++;//计算入度
				Outdegree[i]++;//计算出度,终点都为出度为0的点
			}
	while (v != -1)
	{
		v = -1;
		for (int i = 0; i < Nv; i++)
			if (Indegree[i] == 0 && visit[i]== 0)//入度为0并且没有算过最早工期
			{
				visit[i] = 1;                    //接下来要算这个活动的最早工期了,下次就不算它了
				v = i;
				break;
			}
		if (v != -1)
		{
			Earliest[v] = early(v);      //只有入度为0的才可以算最早工期
			for (int w = 0; w < Nv; w++) //对v的每一个邻节点进行判断,如果是v的一个出边,那么另一个顶点的入度减1
			{
				if (G[v][w] != INFINITY)
					Indegree[w]--;
			}
			cnt++;//判断每一个顶点是否都计算过最短工期了
		}
		else break;
	}
	if (cnt != Nv)  //如果有回路那么肯定有顶点没有计算过工期
		return false;
	return true; 
}

int islast()//判断终点里面需要最长时间完工的时间
{
	int maxtime = 0;
	for (int i = 0; i < Nv; i++)
	{
		if (Outdegree[i] == 0 && Earliest[i]>maxtime)
			maxtime = Earliest[i];
	}
	return maxtime;
}

int main()
{
	cin >> Nv >> Ne;
	BuildGraph();
	if (TopSort())
		cout << islast();
	else
		cout << "Impossible";
	return 0;
}

猜你喜欢

转载自blog.csdn.net/yuquan87/article/details/80195514