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.
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;
}