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