求有向无环图的所有拓扑序列

腰酸背痛一个上午,终于搞定了。。

一 用到二个工具:

1.回溯法的算法思想

2.顺序表(主要用到了删除操作)

二 程序设计步骤:

1.读入图;

这里我没有用严格的图结构。而是用邻接矩阵来表示图,邻接矩阵放在一个txt文件中。(见后文)

读入图就是指读入这个文件。

2.计算图中顶点的入度;

用一个结构体数组来存放顶点名称和顶点的入度(我这里的结构体名称是ElemType)

3.初始化顺序表

这一步只需初始化第0号顺序表。。。

用2中的顶点入度数组来初试化。

4.开始计算拓扑序列

这里我们把图的每个顶点比作一个球,每个顺序表比作一个袋子。

假设图有十个顶点,则需要十个袋子。(100个顶点,需要100个袋子。。。)

这个问题与常见回溯算法不同的一个特点:从前一个袋子里取出球后,才能知道下一个袋子里装的是那几个球。

思想如下:

(1)将所有的球装入第0号袋子;

(2)从袋子中取出一个球。如果合法(即入度为0),进行下一步;如果非法(即入度不为0),取下一个球。

(3)根据(2)中取出的球,计算下一个袋子中的球的情况。上一步袋子中的球,除去取出的球外,全部放入下一个袋子(假设为A号袋子)中。根据取出的球(即顶点),

计算A号袋子中球(即顶点)的入度。

(4)重复步骤(2),每次袋子中都会少一颗球,直到最后一个袋子。取球的顺序即该图的一个拓扑排序;

(5)从最后一个袋子开始回溯,直到回到第0号袋子,并把第0号袋子中的球取完为止。

5.输出

三 示例

1.需要拓扑排序的图

2.存放邻接矩阵的文件。。

3.代码

(1)我的一个存放顺序表操作的头文件。。

 1 #pragma once
 2 #ifdef ElemType
 3 #else
 4 #define ElemType int
 5 #endif
 6 #ifdef MaxSize
 7 #else
 8 #define MaxSize 10
 9 #endif
10
11 //顺序表
12 struct sqList
13 {
14     ElemType data[MaxSize];
15     int length;
16 };
17 typedef struct sqList SqList;
18
19 //初始化
20 void init(SqList* list)
21 {
22     list->length = 0;
23     return;
24 }
25
26 //求长度
27 int getLength(SqList* list)
28 {
29     return list->length;
30 }
31
32 //插入
33 int insert(SqList* list, int n, ElemType x)
34 {
35     if (list->length >= MaxSize || n < 0 || n > list->length)
36     {
37         return 0;
38     }
39     int i = list->length;
40     while (i > n)
41     {
42         list->data[i] = list->data[i - 1];
43         i--;
44     }
45     list->data[n] = x;
46     list->length++;
47     return 1;
48 }
49
50 //删除
51 int del(SqList* list, int n, ElemType* x)
52 {
53     if (n < 0 || n > list->length - 1)
54     {
55         return 0;
56     }
57     int i = n;
58     *x = list->data[i];
59     while (i < list->length - 1)
60     {
61         list->data[i] = list->data[i + 1];
62         i++;
63     }
64     list->length--;
65     return 1;
66 }

(2)开始求拓扑排序

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 struct elemType
  5 {
  6     int name;    //顶点名称
  7     int num;     //顶点的入度数
  8 };
  9 #define ElemType elemType
 10 #define MaxSize 10
 11 #define ROW 10
 12 #define COL 10
 13 #include"sq-list.h"
 14
 15 SqList bags[COL + 1];     //袋子
 16
 17 int inputGraphic(const char *path, int mGraphic[][COL], int row);
 18 void getInDegree(int mGraphic[][COL], int row, ElemType degs[], int n);
 19 void initList(ElemType degs[], int n);
 20 int permulation(int mGraphic[][COL], int row, int n);
 21 void printResult(int result[], int n);
 22
 23
 24 int main()
 25 {
 26     const char* path = "graphic.txt";
 27     int mGraphic[ROW][COL];
 28     ElemType degs[COL];               //存放图中的顶点信息和入度数
 29     int counter = 0;
 30
 31     if (!inputGraphic(path, mGraphic, ROW))
 32     {
 33         return 0;
 34     }
 35     getInDegree(mGraphic, ROW, degs, COL);
 36     initList(degs, COL);
 37     counter = permulation(mGraphic, ROW, COL);
 38     printf("这个图共有:%d种拓扑排序", counter);
 39     return 0;
 40 }
 41
 42 //读入图
 43 int inputGraphic(const char* path, int mGraphic[][COL], int row)
 44 {
 45     int i, j;
 46     FILE* fp;
 47     fp = fopen(path, "r");
 48     if (fp == NULL)
 49     {
 50         return 0;
 51     }
 52     for (i = 0; i < ROW; i++)
 53     {
 54         for (j = 0; j < COL; j++)
 55         {
 56             fscanf(fp, "%d", &mGraphic[i][j]);
 57         }
 58     }
 59     fclose(fp);
 60     return 1;
 61 }
 62
 63 //计算每个顶点的入度
 64 void getInDegree(int mGraphic[][COL], int row, ElemType degs[], int n)
 65 {
 66     int i, j;
 67     for (j = 0; j < COL; j++)
 68     {
 69         degs[j].name = j;
 70         degs[j].num = 0;
 71         for (i = 0; i < ROW; i++)
 72         {
 73             degs[j].num += mGraphic[i][j];
 74         }
 75     }
 76 }
 77
 78 //初始化顺序表
 79 void initList(ElemType degs[], int n)
 80 {
 81     init(&bags[0]);
 82     int i = 0, j = 0;
 83     for (i = 0; i < n; i++)
 84     {
 85         bags[0].data[i] = degs[i];
 86     }
 87     bags[0].length = n;
 88 }
 89
 90 //计算所有拓扑排序
 91 int permulation(int mGraphic[][COL], int row, int n)
 92 {
 93     int counter = 0;     //计数器,即共多少种排序方式
 94     int i = 0, j = 0;
 95     int temp = 0;
 96     ElemType ball, tempBall;
 97     int* index = (int*)malloc(sizeof(int) * n);
 98     int* result = (int*)malloc(sizeof(int) * n);
 99     if (index == NULL || result == NULL)
100     {
101         return -1;
102     }
103     for (i = 0; i < n; i++)
104     {
105         index[i] = 0;
106     }
107
108     i = 0;
109     while (i >= 0)
110     {
111         //从第i号袋子中,取第index[i]号球
112         if (i < n)
113         {
114             if (bags[i].data[index[i]].num != 0)
115             {
116                 //如果取出的球不合法(即度不为0),则取下一个球
117                 index[i] += 1;
118             }
119             else if (index[i] >= bags[i].length)
120             {
121                 //回溯
122                 //当第i号袋子中所有的球都被取过之后,回溯到第i-1号袋子
123                 //同时要把i~n-1号袋子"还原",即index[i]=0,index[i+1]=0...
124                 //保证再次取到这个袋子时,依然时从0号球开始取
125                 temp = i;
126                 i--;
127                 while (temp < n)
128                 {
129                     index[temp++] = 0;
130                 }
131             }
132             else
133             {
134                 //取出一颗球
135                 result[i] = bags[i].data[index[i]].name;
136                 //生成下一个袋子里的球
137                 bags[i + 1] = bags[i];
138                 del(&bags[i + 1], index[i], &tempBall);
139                 for (j = 0; j < bags[i + 1].length; j++)
140                 {
141                     ball = bags[i + 1].data[j];
142                     if (mGraphic[tempBall.name][ball.name] == 1)
143                     {
144                         bags[i + 1].data[j].num--;
145                     }
146                 }
147                 //下次在从i号袋子里取球时,取index[i]+1号球
148                 index[i] += 1;
149                 //从下一个袋子里取球
150                 i++;
151             }
152         }
153         else
154         {
155             counter++;
156             printResult(result, n);
157             i--;
158         }
159     }
160
161     return counter;
162     free(index);
163     free(result);
164 }
165
166 void printResult(int result[], int n)
167 {
168     int i = 0;
169     for (i = 0; i < n; i++)
170     {
171         //此处加1是因为图中顶点是从1开始编号的,而程序中顶点从0开始编号
172         printf("%d,", result[i] + 1);
173     }
174     printf("\n");
175 }

原文地址:https://www.cnblogs.com/ben-/p/12531472.html

时间: 2024-10-03 18:14:09

求有向无环图的所有拓扑序列的相关文章

[从今天开始修炼数据结构]无环图的应用 —— 拓扑排序和关键路径算法

上一篇文章我们学习了最短路径的两个算法.它们是有环图的应用.下面我们来谈谈无环图的应用. 一.拓扑排序 博主大学学的是土木工程,在老本行,施工时很关键的节约人力时间成本的一项就是流水施工,钢筋没绑完,浇筑水泥的那帮兄弟就得在那等着,所以安排好流水施工,让工作周期能很好地衔接就很关键.这样的工程活动,抽象成图的话是无环的有向图. 在表示工程的有向图中,用顶点表示活动,弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,成为AOV网(Active On Vertex Network) ※ 若在

图的邻接表表示与无环图的拓扑排序

一.  图的最常用的表示方法是邻接矩阵和邻接表. 1,邻接矩阵 邻接矩阵其实就是一个二维数组,对于每条边<u,v>,我们就令A[u][v] = 1,如果图为有权图,我们也可以令A[u][v]等于该权,这么表示的优点是非常简单,但是它的空间需求很大,如果图是稠密的,邻接矩阵是合适的表示方法,如果图是稀疏的,那这种方法就太浪费空间了,下面给出图的邻接矩阵表示例子. 2 邻接表 邻接表是图的常用储存结构之一.邻接表由表头结点和表结点两部分组成,其中图中每个顶点均对应一个存储在数组中的表头结点.如下图

HDU 3249 Test for job (有向无环图上的最长路,DP)

 解题思路: 求有向无环图上的最长路,简单的动态规划 #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <algorithm> #include <vector> #include <cmath> #define LL long long using namespace std; const int

48. 蛤蟆的数据结构笔记之四十八的有向无环图的应用关键路径

48. 蛤蟆的数据结构笔记之四十八的有向无环图的应用关键路径 本篇名言:"富贵不淫贫贱乐 ,男儿到此是豪雄.-- 程颢" 这次来看下有向无环图的另一个应用关键路径. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47135061 1.  关键路径 与AOV-网相对应的是AOE-网(Activity On Edge)即边表示活动的网.AOE-网是一个带权的有向无环图,其中,顶点表示事件(Event),弧表示活动,权表

有向无环图的最小路径覆盖 二分图模型解题

有向无环图中,路径覆盖就是在图中找一些路径,使之覆盖了图中的所有顶点,且任何一个顶点有且只有一条路径与之关联(如果把这些路径中的每条路径从它的起始点走到它的终点,那么恰好可以经过图中的每个顶点一次且仅一次). 最小路径覆盖就是找出最小的路径条数,使之成为原图的一个路径覆盖. 公式:最小路径覆盖=(原图)顶点数-对应的二分图的最大匹配数. 我们通过例题来解释如何把DAG转换为二分图模型. HDU1151Air Raid 题目大意:在一个城镇,有n个路口,和m条单向路,而且这些路不会形成环.现在要弄

有向无环图的应用—AOV网 和 拓扑排序

有向无环图:无环的有向图,简称 DAG (Directed Acycline Graph) 图. 一个有向图的生成树是一个有向树,一个非连通有向图的若干强连通分量生成若干有向树,这些有向数形成生成森林. 在工程计划和管理方面的应用 除最简单的情况之外,几乎所有的工程都可分为若干个称作“活动”的子工程,并且这些子工程之间通常受着一定条件的约束,例如:其中某些子工程必须在另一些子工 程完成之后才能开始.对整个工程和系统,人们关心的是两方面的问题: 一是工程能否顺利进行,即工程流程是否“合理”: 二是

【数据结构】拓扑排序、最短路径算法、Dijkstra算法、无环图等等

图的定义 图(graph)G = (V,E)由顶点(vertex)的集V和边(Edge)的集E组成.有时也把边称作弧(arc),如果点对(v,w)是有序的,那么图就叫做有向的图(有向图).顶点v和w邻接(adjacent)当且仅当(v,w)属于E. 如果无向图中从每一个顶点到其他每个顶点都存在一条路径,则称该无向图是连通的(connected).具有这样性质的有向图称为是强连通的(strongly connected).如果有向图不是强连通的,但它的基础图(underlying graph)(也

【拓扑】【宽搜】CSU 1084 有向无环图 (2016湖南省第十二届大学生计算机程序设计竞赛)

题目链接: http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1804 题目大意: 一个有向无环图(DAG),有N个点M条有向边(N,M<=105),每个点有两个值ai,bi(ai,bi<=109),count(i,j)表示从i走到j的方案数. 求mod 109+7的值. 题目思路: [拓扑][宽搜] 首先将式子拆开,每个点I走到点J的d[j]一次就加上一次ai,这样一个点被i走到的几次就加上几次ai,相当于count(i,j)*ai,最终只要求

数据结构与算法——有向无环图的拓扑排序C++实现

拓扑排序简介: 拓扑排序是对有向无环图的顶点的一种排序,它使得如果存在一条从Vi到Vj的路径,那么在排序中Vi在Vj的前面. 如果图中含有回路,那么拓扑排序是不可能的.此外,拓扑排序不必是唯一的,任何合理的排序都可以. 对于上面的无环图:v1,v2,v5,v4,v3,v7,v6和v1,v2,v5,v4,v7,v3,v6都是合理的拓扑排序. 一个简单的求拓扑排序的思路: 1.先找出任意一个没有入边的顶点 2.然后显出该点,并将它和它邻接的所有的边全部删除. 3.然后,对图中其它部分做同样的处理.