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
题目基本大意:
给定一个AOE图,要求输出该项目的最早完成时间,否则输出“Impossible”(即当该图有环时输出“Impossible”)。
解题思路:
解决该问题就是要利用拓扑排序(加一个记录每个事件的最早完成时间的数组)即可得到每个事件(即顶点)的最早完成时间,而题目要求输出的最大的事件的最早完成时间(即终点)(注意注意,终点并不是序号最大的那个顶点哦,而是最早完成时间最大的那个点哦),而检查一个该图是否为有向无环图(DAG)只需要加一个计数变量就可以啦~
拓扑排序:
(拓扑序:如果v到w有一条有向边,那v一定排在w的前面,这样的序列成为拓扑序。)
得到拓扑序的过程就成为拓扑排序。如果能够得到一个合理的拓扑序列,那么可以判断该图为有向无环图(DAG)。
拓扑排序代码:
/* 邻接表存储 - 拓扑排序算法 */
bool TopSort( LGraph Graph, Vertex TopOrder[] )
{ /* 对Graph进行拓扑排序, TopOrder[]顺序存储排序后的顶点下标 */
int Indegree[MaxVertexNum], cnt;
Vertex V;
PtrToAdjVNode W;
Queue Q = CreateQueue( 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]++; /* 对有向边<V, W->AdjV>累计终点的入度 */
/* 将所有入度为0的顶点入列 */
for (V=0; V<Graph->Nv; V++)
if ( Indegree[V]==0 )
AddQ(Q, V);
/* 下面进入拓扑排序 */
cnt = 0;
while( !IsEmpty(Q) ){
V = DeleteQ(Q); /* 弹出一个入度为0的顶点 */
TopOrder[cnt++] = V; /* 将之存为结果序列的下一个元素 */
/* 对V的每个邻接点W->AdjV */
for ( W=Graph->G[V].FirstEdge; W; W=W->Next )
if ( --Indegree[W->AdjV] == 0 )/* 若删除V使得W->AdjV入度为0 */
AddQ(Q, W->AdjV); /* 则该顶点入列 */
} /* while结束*/
if ( cnt != Graph->Nv )
return false; /* 说明图中有回路, 返回不成功标志 */
else
return true;
}
关于如何判断一个图是不是DAG,看:从任一顶点开始遍历,会不会重新遍历到该顶点。
具体方法有两种:
一、BFS。(拓扑排序即是BFS的变形)
二、DFS。
代码(拓扑排序):
#include<stdio.h>
#define MaxSize 101
#define INF 1000
#include<queue>
using namespace std;
int N,M,etime[MaxSize];//存储最早完成时间
int G[MaxSize][MaxSize];//有向图
int Indegree[MaxSize];//装各个顶点的入度
queue<int>Q;
void CreateGraph(){
//建图
int i,j,k;
scanf("%d%d",&N,&M);
for(i=0;i<N;i++){
for(j=0;j<N;j++){
if(i==j)G[i][j]=0;
else G[i][j]=INF;
}
}
for(k=0;k<M;k++){
scanf("%d%d",&i,&j);
scanf("%d",&G[i][j]);
}
while(!Q.empty())Q.pop();
}
bool TopSort(){
//拓扑排序
int i,j,v,w;
int count=0;
for(i=0;i<N;i++){
Indegree[i]=etime[i]=0;
for(j=0;j<N;j++){
if(i!=j&&G[j][i]!=INF) {
Indegree[i]++;
}
}
if(Indegree[i]==0){
Q.push(i);
etime[i]=0;
}
}
while(!Q.empty()){
v=Q.front();
Q.pop();
count++;
for(i=0;i<N;i++){
if(v!=i&&G[v][i]!=INF){
Indegree[i]--;
if(Indegree[i]==0)Q.push(i);
if(etime[v]+G[v][i]>etime[i])etime[i]=etime[v]+G[v][i];
}
}
}
if(count!=N)return false;
return true;
}
int MaxEtime(){
//找出该图的终点,即etime[]值最大的那个点
int i,Maxnum=etime[N-1];
for(i=0;i<N-1;i++){
if(etime[i]>Maxnum) Maxnum=etime[i];
}
return Maxnum;
}
int main(){
CreateGraph();
if(!TopSort())printf("Impossible");
else
printf("%d",MaxEtime());//终点不一定是顶点编号最大的那个点哦
return 0;
}
提交结果:
希望对你有所帮助鸭~