前置知识:
拓扑排序:
/* 邻接表存储 - 拓扑排序算法 */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; /* 说明图中有回路, 返回不成功标志 */ elsereturn true;
}
题目详情:
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
简单翻译:
第i行实际上给出的是一条有向边的信息,包括这条边的起点,终点和权值,要求在对这些事件进行拓扑排序后找到完成这系列事件所需时间,暂未涉及到关键路径问题,不要想复杂
主要思路:
难点:
(一)如何建图
第i行实际上给出的是一条有向边的信息,包括这条边的起点,终点和权值
用邻接矩阵建图应该也可以,不过锻炼能力还是用邻接表建图
(二)如何遍历
拓扑排序
关键一:
Earliest的更新:Earliest[i]表示完成节点i所需的最早时间单位,但因为存在不同的依赖关系,所以在若干前置事件完成后必须从中挑出一个最大的
关键二:
不是vertexNums-1就是结束事件,而是要在Earliest数组中找到最大值
代码实现:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#define MAX_NODE_NUMS 105
#define TRUE 1
#define FALSE 0
#define NONE -1
typedef int bool;
/*实现队列的数据结构*/
typedef struct QueueNode QueueNode;
typedef QueueNode* Queue;
struct QueueNode {int Head, Rear, Size;int Data[MAX_NODE_NUMS];
};
void InitQueue(Queue* q) {(*q)->Head = 0;(*q)->Rear = -1;(*q)->Size = 0;for(int i = 0; i < MAX_NODE_NUMS; i++) {(*q)->Data[i] = NONE;}
}
bool IsEmpty(Queue* q) {if((*q)->Size == 0) {return TRUE;}else {return FALSE;}
}
bool IsFull(Queue* q) {if((*q)->Size == MAX_NODE_NUMS) {return TRUE;}else {return FALSE;}
}
void Enqueue(Queue* q, int data) {if(!IsFull(q)) {(*q)->Data[((*q)->Rear + 1) % MAX_NODE_NUMS] = data;(*q)->Rear = ((*q)->Rear + 1) % MAX_NODE_NUMS;(*q)->Size++;return;}
}
int Dequeue(Queue* q) {if(!IsEmpty(q)) {int ret = (*q)->Data[(*q)->Head];(*q)->Head = ((*q)->Head + 1) % MAX_NODE_NUMS;(*q)->Size--;return ret;}
}
/*实现邻接表构造的图的数据结构*/
typedef struct EdgeNode EdgeNode;
typedef EdgeNode* PToEdge;
struct EdgeNode {int Start, End, Weight;
};
typedef struct AdjVNode AdjVNode;
typedef AdjVNode* PToAdjVNode;
struct AdjVNode {int Index;int Weight;PToAdjVNode Next;
};
typedef struct HeadNode HeadNode;
struct HeadNode {int Data;PToAdjVNode FirstEdge;
};
typedef struct ListGraphNode ListGraphNode;
typedef ListGraphNode* ListGraph;
struct ListGraphNode {int VertexNums, EdgeNums;HeadNode Head[MAX_NODE_NUMS];
};
ListGraph CreateEmptyGraph(int vertexNums) {ListGraph graph = (ListGraph)malloc(sizeof(ListGraphNode));graph->VertexNums = vertexNums;for(int i = 0; i < graph->VertexNums; i++) {graph->Head[i].FirstEdge = NULL;}return graph;
}
/*注意,这里插入的是有向边*/
void InsertEdge(PToEdge edge, ListGraph graph) {PToAdjVNode newNode = (PToAdjVNode)malloc(sizeof(AdjVNode));newNode->Index = edge->End;newNode->Weight = edge->Weight;newNode->Next = graph->Head[edge->Start].FirstEdge;graph->Head[edge->Start].FirstEdge = newNode;return;
}
ListGraph BuildGraph(int vertexNums, int edgeNums) {ListGraph graph = CreateEmptyGraph(vertexNums);graph->EdgeNums = edgeNums;for(int i = 0; i < edgeNums; i++) {PToEdge edge = (PToEdge)malloc(sizeof(EdgeNode));scanf("%d %d %d", &(edge->Start), &(edge->End), &(edge->Weight));InsertEdge(edge, graph);free(edge);}return graph;
}
int InDegree[MAX_NODE_NUMS];
int Earliest[MAX_NODE_NUMS];
void TopSort(ListGraph graph) {/*初始化*/for(int i = 0; i < graph->VertexNums; i++) {for(PToAdjVNode p = graph->Head[i].FirstEdge; p; p = p->Next) {InDegree[p->Index]++;}}Queue q = (Queue)malloc(sizeof(QueueNode));InitQueue(&q);int Vcount = 0;for(int i = 0; i < graph->VertexNums; i++) {if(InDegree[i] == 0) {Enqueue(&q, i);Earliest[i] = 0;}} while(!IsEmpty(&q)) {int vertexIndex = Dequeue(&q);Vcount++;for(PToAdjVNode p = graph->Head[vertexIndex].FirstEdge; p; p = p->Next) {if(Earliest[p->Index] < Earliest[vertexIndex] + p->Weight) {Earliest[p->Index] = Earliest[vertexIndex] + p->Weight;}if(--InDegree[p->Index] == 0) {Enqueue(&q, p->Index);}}}if(Vcount != graph->VertexNums) {printf("Impossible");}else {int max = 0;for(int i = 0; i < graph->VertexNums; i++) {if(Earliest[i] > max) {max = Earliest[i];}}printf("%d", max);}
}
int main() {int vertexNums, edgeNums;scanf("%d %d", &vertexNums, &edgeNums);ListGraph graph = BuildGraph(vertexNums, edgeNums);TopSort(graph);system("pause");return 0;
}