08-图8 How Long Does It Take(25 分)
题目地址: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.
输入格式:
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.输出格式:
For each test case, if the scheduling is possible, print in a line its earliest completion time; or simply output “Impossible”.
Tips:
这题考查的是拓扑排序。会写拓扑排序应该没问题,但是有两个易错点需要注意:
1. 最终完工时间未必是最后一个结点完成的时间,因为可能有多个“结束结点”,最终的完成时间取决于这些结点中时间最长的一个。
2. 我在下面程序中做了标记(########),在我标记的for循环内,千万不要拿来更新EarlyVertexNum,我一开始就是这么写的,结果有两个测试样例通不过,我来我想了一下,如果对题目给的输入样例以来说,倒着输结点之间的权重,更新就会出问题。
程序:
#include <iostream>
#include <queue>
#include <cstdlib>
#include <cstdio>
using namespace std;
#define MaxVertexNum 105
typedef int WeightType;
typedef int Vertex;
int EarlyStart[MaxVertexNum] = {0};
/* 边定义 */
typedef struct ENode* Edge;
struct ENode
{
Vertex V1, V2;
WeightType Weight;
};
/* 邻接点定义 */
typedef struct AdjNode* PtrToAdjNode;
struct AdjNode
{
Vertex AdjV; // 邻接点下标
WeightType Weight;
PtrToAdjNode next;
};
/* 顶点表头结点定义*/
typedef struct VNode
{
PtrToAdjNode FirstEdge;
}AdjList[MaxVertexNum];
typedef struct GNode* LGraph;
struct GNode
{
int Nv; // 顶点数
int Ne; // 边数
AdjList G;
};
void InsertEdge(Edge E, LGraph Graph)
{ /* 头插法 插入边<V1, V2> */
PtrToAdjNode NewNode = (PtrToAdjNode)malloc(sizeof(AdjNode));
NewNode->AdjV = E->V2;
NewNode->Weight = E->Weight;
NewNode->next = Graph->G[E->V1].FirstEdge;
Graph->G[E->V1].FirstEdge = NewNode;
}
LGraph InitialGraph(int Nv)
{ /* 初始化图 */
LGraph Graph = (LGraph)malloc(sizeof(GNode));
Graph->Nv = Nv;
Graph->Ne = 0;
for (int i = 0; i < Nv; i++)
Graph->G[i].FirstEdge = NULL;
return Graph;
}
LGraph BuildGraph(LGraph Graph)
{ /* 建立边联系 */
cin >> Graph->Ne;
for (int i = 0; i < Graph->Ne; i++)
{
Edge E = (Edge)malloc(sizeof(ENode));
cin >> E->V1 >> E->V2 >> E->Weight;
InsertEdge(E, Graph);
}
return Graph;
}
bool TopSort(LGraph Graph)
{ /* 拓扑排序 */
int Indegree[MaxVertexNum] = {0}, cnt = 0; // 初始化入度
PtrToAdjNode W;
for (int i = 0; i < Graph->Nv; i++)
{
for (W = Graph->G[i].FirstEdge; W; W = W->next) /* ########################## */
Indegree[W->AdjV]++; // 入度+1
queue <Vertex> Q;
for (Vertex V = 0; V < Graph->Nv; V++)
{ /* 将入度为0的结点下标放入队列 */
if (Indegree[V] == 0)
Q.push(V);
}
while (!Q.empty())
{
Vertex V = Q.front();
Q.pop();
cnt++; // 每出队一个元素cnt+1
for (W = Graph->G[V].FirstEdge; W; W = W->next)
{
if (EarlyStart[W->AdjV] < W->Weight + EarlyStart[V]) // 更新最早开工时间
EarlyStart[W->AdjV] = W->Weight + EarlyStart[V];
Indegree[W->AdjV]--; // 把所有的前驱结点为V的顶点的入度-1
if (Indegree[W->AdjV] == 0)
Q.push(W->AdjV);
}
}
if (cnt != Graph->Nv)
return false;
else
return true;
}
int main(int argc, char const *argv[])
{
int N;
cin >> N;
LGraph Graph = InitialGraph(N);
Graph = BuildGraph(Graph);
if (!TopSort(Graph))
cout << "Impossible" << endl;
else
{
int Max = 0;
for (int i = 0; i < N; i++) // 因为最长时间不一定在最后一个点
if (EarlyStart[i] > Max)
Max = EarlyStart[i];
cout << Max << endl;
}
return 0;
}