【拓扑排序】有向图的拓扑排序

问题描述

给定一个 n 个点 m 条边的有向图,点的编号是 1 到 n,图中可能存在重边和自环。

请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出 −1。

若一个由图中所有点构成的序列 A 满足:对于图中的每条边 (x,y),x 在 A 中都出现在 y 之前,则称 A 是该图的一个拓扑序列。

输入格式
第一行包含两个整数 n 和 m

接下来 m 行,每行包含两个整数 x 和 y,表示存在一条从点 x 到点 y 的有向边 (x,y)。

输出格式
共一行,如果存在拓扑序列,则输出任意一个合法的拓扑序列即可。

否则输出 −1

问题求解

拓扑排序
依次删除入度为0的点以及它发出的边

如果最后全部点都被删除完全,则成功进行拓扑排序
否则,输出-1

首先记录各个点的入度

然后将入度为 0 的点放入队列

将队列里的点依次出队列,然后找出所有出队列这个点发出的边,删除边,同事边的另一侧的点的入度 -1。

如果所有点都进过队列,则可以拓扑排序,输出所有顶点。否则输出-1,代表不可以进行拓扑排序

在这里插入图片描述

代码实现

# include <iostream>
# include <queue>
# include <vector>
# include<cstring>
# include <algorithm>


using namespace std;

const int N = 100010;
queue<int> q;
vector<int> v;

int e[N], ne[N],h[N];
int d[N];//计算每个点的入度数
int idx;
int n,m;
int sum;


void add(int a, int b){
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx++;
}

void topsort(){
    //找度为0的点
    for(int i =1; i<=n; i++){
        if(d[i]==0){
            q.push(i);
        }
    }
    
    while(!q.empty()){
        int u = q.front();
        v.push_back(u);
        sum++;
        q.pop();
        for(int j = h[u]; j!=-1; j=ne[j]){
            int c = e[j];
            d[c]--;
            if(d[c]==0){
                q.push(c);
            }
        }
    }
    
    if(sum == n){
        for(auto i : v){
            cout<<i<<" ";
        }
    }
    else{
        cout<<-1;
    }
    
    
    
}

int main(){
    memset(h, -1, sizeof(h));
    cin>>n>>m;
    int a,b;
    for(int i =0 ;i<m ;i++){
        cin>>a>>b;
        add(a,b);
        d[b]++;
    }
    topsort();
    
}

  • 13
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。
### 回答1: C语言可以使用邻接表来存储一个,并且可以通过拓扑排序算法来输出拓扑排序结果。 首先,我们需要定义一个结构体来表示的顶点和边。结构体包含一个顶点的标识符和一个指向链表的指针,用于存储与该顶点相邻的顶点。 ```c // 定义的顶点结构体 struct Vertex { int id; // 顶点的标识符 struct Vertex* next; // 指向相邻顶点的链表 }; ``` 接下来,我们可以使用数组来创建一个顶点列表,每个数组元素都是一个指向顶点结构体的指针。 ```c struct Vertex* graph[100]; ``` 然后,我们可以编写一个函数来将边添加到中。该函数将接受两个顶点的标识符作为参数,并将边添加到顶点的链表中。 ```c // 向中添加边 void addEdge(int from, int to) { struct Vertex* vertex = (struct Vertex*) malloc(sizeof(struct Vertex)); vertex->id = to; vertex->next = graph[from]; graph[from] = vertex; } ``` 接下来,我们需要编写一个拓扑排序函数来输出拓扑排序结果。拓扑排序使用深度优先搜索算法来访问所有顶点,并利用栈来记录访问的顶点。 ```c // 深度优先搜索 void dfs(int v, int visited[], struct Vertex* stack[], int* top) { visited[v] = 1; struct Vertex* vertex = graph[v]; while (vertex != NULL) { int id = vertex->id; if (!visited[id]) { dfs(id, visited, stack, top); } vertex = vertex->next; } stack[*top] = graph[v]; (*top)++; } // 拓扑排序 void topologicalSort(int numVertices) { int visited[100] = {0}; // 记录顶点是否已访问 struct Vertex* stack[100]; int top = 0; for (int i = 0; i < numVertices; i++) { if (!visited[i]) { dfs(i, visited, stack, &top); } } printf("拓扑排序结果:"); for (int i = top - 1; i >= 0; i--) { printf("%d ", stack[i]->id); } printf("\n"); } ``` 最后,我们可以在主函数中构建并调用拓扑排序函数来输出拓扑排序结果。 ```c int main() { // 构建 addEdge(0, 1); addEdge(0, 2); addEdge(1, 3); addEdge(2, 3); addEdge(2, 4); addEdge(3, 4); // 输出拓扑排序 topologicalSort(5); return 0; } ``` 以上代码将输出拓扑排序结果:0 2 1 3 4。这是的一种拓扑排序方式。 ### 回答2: C语言可以通过邻接表来存储一个。邻接表是一种数据结构,用来表示中的顶点和边的关系。在邻接表中,的顶点被表示为一个数组,每个顶点都有一个链表,链表中存储了与该顶点相邻的其他顶点。 实现一个拓扑排序,可以利用邻接表和深度优先搜索算法。 首先,定义一个结构体来表示的顶点和边: ``` typedef struct Node { int val; struct Node* next; } Node; typedef struct Graph { int numVertices; Node** adjLists; } Graph; ``` 接下来,我们需要实现的初始化和添加边的函数: ``` Graph* createGraph(int numVertices) { Graph* graph = (Graph*)malloc(sizeof(Graph)); graph->numVertices = numVertices; graph->adjLists = (Node**)malloc(numVertices * sizeof(Node*)); for (int i = 0; i < numVertices; i++) { graph->adjLists[i] = NULL; } return graph; } void addEdge(Graph* graph, int src, int dest) { // 添加一条边从顶点src到dest Node* newNode = createNode(dest); newNode->next = graph->adjLists[src]; graph->adjLists[src] = newNode; } ``` 接下来,我们需要实现拓扑排序算法。拓扑排序通过深度优先搜索来遍历的顶点,并按照遍历的顺序输出拓扑排序结果。具体实现如下: ``` void topologicalSortUtil(int v, bool visited[], Graph* graph, Stack* stack) { // 将当前顶点标记为已访问 visited[v] = true; Node* adjList = graph->adjLists[v]; while (adjList != NULL) { int adjVertex = adjList->val; if (!visited[adjVertex]) { topologicalSortUtil(adjVertex, visited, graph, stack); } adjList = adjList->next; } // 将当前顶点推入栈中 push(stack, v); } void topologicalSort(Graph* graph) { Stack* stack = createStack(); bool visited[graph->numVertices]; for (int i = 0; i < graph->numVertices; i++) { visited[i] = false; } for (int i = 0; i < graph->numVertices; i++) { if (!visited[i]) { topologicalSortUtil(i, visited, graph, stack); } } // 输出拓扑排序结果 while (!isEmpty(stack)) { printf("%d ", pop(stack)); } free(stack); } ``` 利用上述的代码,我们就可以通过邻接表来存储一个,并输出它的一个拓扑排序了。 ### 回答3: 拓扑排序是对有向无环(DAG)进行排序的一种算法,用于表示任务的依赖关系或事件发生的顺序。 在C语言中,我们可以使用邻接表来存储一个,并通过拓扑排序算法输出其拓扑排序的结果。 首先,我们需要定义一个结构体来表示中的每个节点: ```c struct Node { int value; struct Node* next; }; ``` 然后,我们可以创建一个邻接表数组,其中每个索引位置对应一个节点: ```c struct Node* adjacencyList[MAX_SIZE]; ``` 接下来,我们可以编写一个函数来添加边到中: ```c void addEdge(int src, int dest) { struct Node* newNode = (struct Node*)malloc(sizeof(struct Node)); newNode->value = dest; newNode->next = adjacencyList[src]; adjacencyList[src] = newNode; } ``` 接着,我们可以编写一个DFS函数来实现拓扑排序: ```c void dfs(int vertex, bool visited[], struct Node* stack) { visited[vertex] = true; struct Node* temp = adjacencyList[vertex]; while (temp != NULL) { int adjVertex = temp->value; if (!visited[adjVertex]) { dfs(adjVertex, visited, stack); } temp = temp->next; } struct Node* newVertex = (struct Node*)malloc(sizeof(struct Node)); newVertex->value = vertex; newVertex->next = stack; stack = newVertex; } ``` 最后,我们可以编写一个函数来调用DFS并输出拓扑排序的结果: ```c void topologicalSort() { bool visited[MAX_SIZE]; struct Node* stack = NULL; for (int i = 0; i < MAX_SIZE; i++) { visited[i] = false; } for (int i = 0; i < MAX_SIZE; i++) { if (!visited[i]) { dfs(i, visited, stack); } } while (stack != NULL) { printf("%d ", stack->value); stack = stack->next; } } ``` 通过以上步骤,我们可以用C语言实现一个以邻接表存储的,并输出其拓扑排序的结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值