本专栏持续输出数据结构题目集,欢迎订阅。
题目
请编写程序,实现求带权的有向图中关键活动的算法。
输入格式:
输入首先在第一行给出两个正整数,依次为当前要创建的图的顶点数 n(≤100)和边数 m。
随后 m 行,每行给出一条有向边的起点编号、终点编号、权重。顶点编号从 0 开始,权重(≤100)为整数。同行数字均以一个空格分隔。
输出格式:
按格式 <u, v> 输出关键活动,其中 u 为起点编号,v 为终点编号。按起点编号的升序,每行输出一个活动。起点编号相同时,与输入的顺序相反,即先输入的边后输出。
最后一行输出 关键路径分析结果为 x,其中 x 为 1 表示关键路径已成功求出,为 0 表示不成功。
输入样例 1:
9 12
0 1 5
0 2 3
1 4 4
1 5 2
2 3 6
2 4 1
3 6 7
4 6 3
4 7 5
5 7 6
6 8 2
7 8 8
输出样例 1:
<0, 1>
<1, 4>
<4, 7>
<7, 8>
关键路径分析结果为 1
输入样例 2:
8 9
0 2 3
0 4 5
1 2 12
1 4 7
3 4 9
4 5 2
4 6 1
5 7 2
7 4 41
输出样例 2:
关键路径分析结果为 0
代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_VERTICES 100
#define INF 999999999
typedef struct Node {
int vertex;
int weight;
int input_order; // 记录输入顺序
struct Node* next;
} Node;
typedef struct {
Node* head;
} AdjList;
typedef struct {
int n, m;
AdjList adj[MAX_VERTICES];
int in_degree[MAX_VERTICES];
int out_degree[MAX_VERTICES];
} Graph;
Node* createNode(int v, int w, int order) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->vertex = v;
newNode->weight = w;
newNode->input_order = order;
newNode->next = NULL;
return newNode;
}
Graph* createGraph(int n, int m) {
Graph* graph = (Graph*)malloc(sizeof(Graph));
graph->n = n;
graph->m = m;
for (int i = 0; i < n; i++) {
graph->adj[i].head = NULL;
graph->in_degree[i] = 0;
graph->out_degree[i] = 0;
}
return graph;
}
void addEdge(Graph* graph, int src, int dest, int weight, int order) {
Node* newNode = createNode(dest, weight, order);
newNode->next = graph->adj[src].head;
graph->adj[src].head = newNode;
graph->in_degree[dest]++;
graph->out_degree[src]++;
}
// 拓扑排序获取顶点顺序
int topologicalSort(Graph* graph, int* order) {
int queue[MAX_VERTICES];
int front = 0, rear = 0;
int count = 0;
int in_degree_copy[MAX_VERTICES];
for (int i = 0; i < graph->n; i++) {
in_degree_copy[i] = graph->in_degree[i];
if (in_degree_copy[i] == 0) {
queue[rear++] = i;
}
}
while (front < rear) {
int u = queue[front++];
order[count++] = u;
Node* current = graph->adj[u].head;
while (current != NULL) {
int v = current->vertex;
in_degree_copy[v]--;
if (in_degree_copy[v] == 0) {
queue[rear++] = v;
}
current = current->next;
}
}
return count == graph->n;
}
// 计算事件的最早发生时间
void computeVE(Graph* graph, int* order, int* ve) {
for (int i = 0; i < graph->n; i++) {
ve[i] = 0;
}
for (int i = 0; i < graph->n; i++) {
int u = order[i];
Node* current = graph->adj[u].head;
while (current != NULL) {
int v = current->vertex;
int w = current->weight;
if (ve[u] + w > ve[v]) {
ve[v] = ve[u] + w;
}
current = current->next;
}
}
}
// 计算事件的最晚发生时间
void computeVL(Graph* graph, int* order, int* ve, int* vl) {
int max_ve = 0;
for (int i = 0; i < graph->n; i++) {
if (ve[i] > max_ve) {
max_ve = ve[i];
}
}
for (int i = 0; i < graph->n; i++) {
vl[i] = max_ve;
}
for (int i = graph->n - 1; i >= 0; i--) {
int u = order[i];
Node* current = graph->adj[u].head;
while (current != NULL) {
int v = current->vertex;
int w = current->weight;
if (vl[v] - w < vl[u]) {
vl[u] = vl[v] - w;
}
current = current->next;
}
}
}
// 比较函数,用于按要求排序活动
int compare(const void* a, const void* b) {
Node* nodeA = (Node*)a;
Node* nodeB = (Node*)b;
if (nodeA->vertex != nodeB->vertex) {
return nodeA->vertex - nodeB->vertex;
}
return nodeB->input_order - nodeA->input_order;
}
int main() {
int n, m;
scanf("%d %d", &n, &m);
Graph* graph = createGraph(n, m);
for (int i = 0; i < m; i++) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
addEdge(graph, u, v, w, i);
}
int order[MAX_VERTICES];
// 执行拓扑排序
if (!topologicalSort(graph, order)) {
printf("关键路径分析结果为 0\n");
return 0;
}
int ve[MAX_VERTICES], vl[MAX_VERTICES];
computeVE(graph, order, ve);
computeVL(graph, order, ve, vl);
// 检查是否存在汇点(出度为0且ve等于最大ve的顶点)
int hasSink = 0;
for (int i = 0; i < n; i++) {
if (graph->out_degree[i] == 0 && ve[i] == vl[i]) {
hasSink = 1;
break;
}
}
if (!hasSink) {
printf("关键路径分析结果为 0\n");
return 0;
}
// 收集所有活动并计算e和l
Node activities[MAX_VERTICES * MAX_VERTICES];
int count = 0;
for (int u = 0; u < n; u++) {
Node* current = graph->adj[u].head;
while (current != NULL) {
int v = current->vertex;
int w = current->weight;
int e = ve[u];
int l = vl[v] - w;
if (e == l) {
activities[count].vertex = u;
activities[count].weight = v;
activities[count].input_order = current->input_order;
count++;
}
current = current->next;
}
}
// 按起点编号升序,起点相同时按输入顺序降序排序
qsort(activities, count, sizeof(Node), compare);
// 输出关键活动
for (int i = 0; i < count; i++) {
printf("<%d, %d>\n", activities[i].vertex, activities[i].weight);
}
printf("关键路径分析结果为 1\n");
return 0;
}
1834

被折叠的 条评论
为什么被折叠?



