求有向无环图的所有拓扑序列
Posted ben-
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求有向无环图的所有拓扑序列相关的知识,希望对你有一定的参考价值。
腰酸背痛一个上午,终于搞定了。。
一 用到二个工具:
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(" "); 175 }
以上是关于求有向无环图的所有拓扑序列的主要内容,如果未能解决你的问题,请参考以下文章