本文改编自CSDN,作者ZhouMu,原文链接如下:
https://blog.csdn.net/zhoujinyu0713/article/details/10163037?utm_source=tuicool
本文的主要工作是,说明拓扑序的含义及其在生成DAG时的妙用,并给原文代码标注释。
0. 拓扑序
这一部分主要参考自百度百科中的“拓扑排序”词条。原文链接如下:
https://baike.baidu.com/item/%E6%8B%93%E6%89%91%E6%8E%92%E5%BA%8F/5223807?fromtitle=%E6%8B%93%E6%89%91%E5%BA%8F&fromid=17352962&fr=aladdin
定义:
对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。
定义中所谓的“偏序”是离散数学中的概念,偏序关系指的是,满足(1)自反性(2)反对称性(3)传递性的关系R。自反性指的是,集合中的任一元素x满足:x R x。反对称性指的是,如果x R y, 则 y R x不成立。传递性指的是,若x R y, y R z, 则有 x R z。
定义中所谓的“全序”也是离散数学中的概念。它在偏序关系的基础上加了限制:集合中任意两个元素都能比较大小。
对有向无环图进行拓扑排序的方法:
1. 生成DAG的思路
假设要生成含有N个节点的网络。首先随机生成一个 1 到N 的排列。这个排列就是DAG的拓扑序,然后每次随机从前往后连边,这样就可以保证生成的是一个DAG了。
2. Python代码及注释
下面是原文的代码。我对代码存在两个疑问:
1. 为啥要在每条边后面加上随机生成的两个数?有什么用意?难道是权重?
2. 为啥在最后生成k个随机数?有什么用?
希望知道的小伙伴能给我讲讲。
- from random import shuffle as sl
- from random import randint as rd
- def gn(): #生成1到1000的一个随机数
- num = rd(1,1000)
- return num
- def w2f(f,num,fg): #将num写入文件f,并根据fg的值决定是否换行
- f.write(str(num))
- if fg==True:
- f.write('\n')
- else:
- f.write(' ')
- def DataMake(c): #生成DAG,存入以c命名的文件内
- MAXL =100000;
- f = open('data'+str(c)+'.in','w')
- n = 1000 #设置图中节点数量
- node = range(1,n+1) #生成1到n的一个序列
- node=list(node) #将格式转换成list,便于下一步随机重排
- sl(node) #随机重排
- sl(node) #随机重排,生成节点的序号。在这里,node[i]的值表示节点,i表示当前节点的拓扑序。
- m = rd(1,min(n*n,5000)) #设置图中边的数量
- w2f(f,n,0);w2f(f,m,1) #将节点数量n和边的数量m写入文件f
- for i in range(0,m): #随机生成m条边
- p1 = rd (1,n-1) #选择第一个节点
- p2 = rd (p1+1,n) #选择第二个节点,这个节点的拓扑序必须大于第一个节点
- x = node[p1-1] #读取拓扑序为p1的节点
- y = node[p2-1] #读取拓扑序为p2的节点
- l = rd(1,MAXL) #生成一个1到MAXL的随机数
- w = gn() #生成一个1到1000的随机数
- w2f(f,x,0);w2f(f,y,0);w2f(f,l,0);w2f(f,w,1) #将x,y,l,w写入文件
- k = gn() #生成一个1到1000的随机数k
- w2f(f,k,1) #将k写入文件
- for i in range(0,k): #生成k个1到1000的随机数
- w2f(f,gn(),1)
- print(n,' node',m,' edges',k,'Queries')
- f.close()
- DataMake(1) #生成一个名为data1.in的文件,里面存储的就是一个DAG
- print ('Done')