油管视频《编程思维》中的题目,使用C语言编写出来,第九集,工厂

题目:假设在一个工厂里,已经有一个设计图,如同给出的示意图显示的生产过程的所有步骤,来制造解药,比如说一个从“添加硝酸”到“剧烈摇晃”的剪头,意味着硝酸需要再摇晃之前加入,如果一个步骤的顺序乱了,解药的制备就失败了,甚至会更糟糕,没有任何循环引用,步骤A对应步骤B或步骤B最终需要对应步骤A,需要将这个复杂的设计图表,转变为一系列的步骤,这就是工厂里工序的顺序,一旦输入,工厂将会根据指示自我重新组装,我的机器人拥有在表中存储信息的能力,请问该给机器人下达什么指令,完成正确的顺序?

涉及的编程基础原理
 

这个问题考察的是拓扑排序(Topological Sorting)和图论的基本知识。

拓扑排序用于对有向无环图(DAG)进行排序,使得对于图中的每一条有向边 u→vu→v,顶点 uu 在排序中出现在顶点 vv 之前。这个问题可以用来模拟工厂中的生产步骤,以确保步骤按正确的顺序执行。

图论基础

图论是数学和计算机科学中的一个分支,研究图的性质和应用。图由顶点(节点)和边(连接顶点的线)组成。根据边的方向性,图可以分为有向图无向图

有向图:边有方向,从一个顶点指向另一个顶点。

无向图:边没有方向,连接两个顶点。

拓扑排序

拓扑排序是一种针对有向无环图(DAG, Directed Acyclic Graph)的排序算法,将图中的顶点排成一个线性序列,使得对于每一条有向边 (u,v)(u,v),顶点 uu 在顶点 vv 之前出现。

拓扑排序在许多应用中很有用,例如任务调度、编译器中的依赖解析等。

1,图论基础:理解有向图、无环图和拓扑排序。

2,数据结构:使用队列和邻接表来存储图和进行排序。

3,算法设计:实现拓扑排序算法(Kahn's Algorithm)。

程序编写

#include <stdio.h> // 包含标准输入输出库,用于使用printf函数输出信息
#include <stdlib.h> // 包含标准库,用于动态内存分配(如malloc)

#define MAX 100 // 定义一个宏MAX,表示图中最大顶点数为100

// 图的邻接表表示
struct Graph {
    int numVertices; // 图中的顶点数
    int* adjLists[MAX]; // 邻接表,用于存储每个顶点的邻接顶点
    int inDegree[MAX]; // 存储每个顶点的入度
};

// 创建图
struct Graph* createGraph(int vertices) {
    struct Graph* graph = (struct Graph*)malloc(sizeof(struct Graph)); // 动态分配内存给图结构
    graph->numVertices = vertices; // 初始化图的顶点数
    
    for (int i = 0; i < vertices; i++) { // 遍历每个顶点
        graph->adjLists[i] = (int*)malloc(vertices * sizeof(int)); // 为每个顶点的邻接表分配内存
        graph->inDegree[i] = 0; // 初始化每个顶点的入度为0
        for (int j = 0; j < vertices; j++) { // 初始化邻接表
            graph->adjLists[i][j] = 0; // 初始化邻接表中的每个值为0
        }
    }
    return graph; // 返回创建的图
}

// 添加边
void addEdge(struct Graph* graph, int src, int dest) {
    graph->adjLists[src][dest] = 1; // 在邻接表中添加边src -> dest
    graph->inDegree[dest]++; // 增加目标顶点的入度
}

// 拓扑排序
void topologicalSort(struct Graph* graph) {
    int queue[MAX], front = 0, rear = 0; // 定义队列和其前后指针,用于存储入度为0的顶点
    int sortedOrder[MAX], index = 0; // 存储排序后的顶点顺序和当前索引
    
    // 将所有入度为0的顶点加入队列
    for (int i = 0; i < graph->numVertices; i++) {
        if (graph->inDegree[i] == 0) { // 如果顶点的入度为0
            queue[rear++] = i; // 将顶点加入队列
        }
    }
    
    while (front < rear) { // 当队列不为空时
        int current = queue[front++]; // 从队列中取出一个顶点
        sortedOrder[index++] = current; // 将顶点加入排序结果
        
        for (int i = 0; i < graph->numVertices; i++) { // 遍历当前顶点的邻接顶点
            if (graph->adjLists[current][i] == 1) { // 如果存在边current -> i
                graph->inDegree[i]--; // 减少目标顶点的入度
                if (graph->inDegree[i] == 0) { // 如果目标顶点的入度变为0
                    queue[rear++] = i; // 将其加入队列
                }
            }
        }
    }
    
    // 检查是否存在环
    if (index != graph->numVertices) { // 如果排序结果中的顶点数不等于图中的顶点数
        printf("图中存在环,无法进行拓扑排序。\n"); // 输出错误信息
        return; // 结束函数
    }
    
    // 输出排序后的顺序
    printf("拓扑排序的顺序为:\n"); // 输出提示信息
    for (int i = 0; i < index; i++) { // 遍历排序结果
        printf("%d ", sortedOrder[i]); // 输出每个顶点
    }
    printf("\n"); // 换行
}

int main() {
    int vertices = 6; // 假设有6个步骤
    struct Graph* graph = createGraph(vertices); // 创建一个包含6个顶点的图
    
    // 根据图示添加边
    addEdge(graph, 0, 2); // 添加边0 -> 2
    addEdge(graph, 0, 3); // 添加边0 -> 3
    addEdge(graph, 1, 3); // 添加边1 -> 3
    addEdge(graph, 1, 4); // 添加边1 -> 4
    addEdge(graph, 2, 5); // 添加边2 -> 5
    addEdge(graph, 3, 5); // 添加边3 -> 5
    addEdge(graph, 4, 5); // 添加边4 -> 5
    
    topologicalSort(graph); // 对图进行拓扑排序
    
    return 0; // 程序正常结束
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值