北航数据结构
在集合 U 中放入顶点 v0,v0 到 v0 的距离为 0。 对 V-U 里的每个顶点 v,如果(v0, v)在 E 中(即存在直接的边),则到 v 的已知最短 路径长度设为 w(v0, v), 否则令 v 的已知最短路径长度为 inf。这里的 w(v0, v)是从 v0 到 v 的 边的权值。 反复做: 从 V-U 中选出当时已知最短路径长度最小的顶点 v(min)加入 U,因为这时到 v(min)的 已知最短路径长度 cdis(v0, v(min))就是 v0 到 v(min)的距离。 由于 v(min)的加入,V-U 中某些顶点的已知最短路径可能改变。如果从 v0 经过 v(min) 到 v'的路径比原来已知的最短路径更短,就说明发现了到 v'的新的已知最短路径(及其长 度),该路径经过 v(min)到 v'。在这种情况下更新到 v'的已知最短路径及距离的记录,保证 下面能正确地继续从 V-U 中选择顶点。 反复选择顶点并更新到所有非 U 顶点的最短路径信息,知道从 v0 可达的所有顶点都在集合 U 中为止。如果这时还存在未加入 U 的顶点,就说明被处理的图不连通。
如果这样做不能得到一个包含 G 的所有顶点的连通分量,则原图不连通,没有最小 生成树。算法做出的是 G 的最小连通树林。 rim 算法 从图 G 的顶点集 V 中任取一顶点(例如 v0)放入集合 U 中,这时 U={v0},令边集合 Er={}, 显然 T=(U,Er)是一棵树(只包含一个顶点且没有边)。
三、算法的设计与实现
Kruskal 算法
设 G=(V,E)是一个网络,其中 IVI=n。 1)初始时取包含 G 中所有 n 个顶点但没有任何边的孤立点子图 T=(V,{}),T 里的每个顶 点自成一个连通分量。下面将通过不断扩充 T 的方式构造 G 的最小生成树。 2)将边集 E 中的边按权值递增的顺序排序,在构造中的每一步顺序地检查这个边序列,找 到下一条(最短的)两端点位于 T 的两个不同连通分量的边 e,把 e 加入 T。这导致两个连 通分量由于边 e 的连接而变成了一个连通分量。 3)每次操作使 T 减少一个连通分量。不断重复这个动作加入新边,直到 T 中所有顶点都包 含在一个连通分量里为止,这个连通分量就是 G 的一棵最小生成树。
p=end l=0 while p>=1 and l<nodes:
road[l]=p p=nodepre[p] l+=1 l-=1 while l>=0: roads.append(road[l]) l-=1 return dis[end],roads def map():
map=[[inf,inf,inf,inf,inf,inf],[inf,inf,inf,6,3,inf,inf,inf],[inf,11, inf,4,inf,inf,7,inf],
return res def prim(self):
res=[] snode=[0] cnode=[i for i in range(1,self.nodenumber)] while len(cnode)>0:
begin,end,min=0,0,99 for i in snode:
for j in cnode: if self.map[i][j]<min: min=self.map[i][j] begin=i
四、结果
Dijkstra
代码 1: class Graph():
def __init__(self,map): self.map=map self.nodenumber=self.nodenumber()
self.edgenumber=self.edgenumber() def nodenumber(self):
一个连通图可能有多个生成树。当图中的边具有权值时,总会有一个生成树的边的权值 之和小于或者等于其它生成树的边的权值之和。广义上而言,对于非连通无向图来说,它的 每一连通分量同样有最小生成树,它们的并被称为最小生成森林。
二、数据结构-图
在数学上,一个图(Graph)是表示物件与物件之间的关系的方法,是图论的基本研究 对象。一个图看起来是由一些小圆点(称为顶点或结点)和连结这些圆点的直线或曲线(称 为边)组成的。如果给图的每条边规定一个方向,那么得到的图称为有向图,其边也称为有 向边。在有向图中,与一个节点相关联的边有出边和入边之分,而与一个有向边关联的两个 点也有始点和终点之分。相反,边没有方向的图称为无向图。
检查所有一个端点在集合 U 里而另一个端点在集合 V-U 的边,找出其中权最小的边 e=(u,v) (假设 u 在 U 中,v 在 V-U 中),将顶点 v 加入顶点集合 U,并将 e 加入边集合 Er。易见, 扩充之后的 T=(U,Er)仍是一棵树。 重复上面步骤直到 U=V(所构造的树已经包含了所有顶点)。这时集合 Er 里有 n-1 条边, 子图 T=(U,Er)就是 G 的一棵最小生成树。 Dijkstra 算法 初始:
if nodedis[j]==0 and dis[j]<minn: t=j minn=dis[j]
nodedis[t]=1 #找到最短的一条路径 ,标记 for j in range(nodes+1):
if nodedis[j]==0 and dis[j]>dis[t]+map[t][j]: dis[j]=dis[t]+map[t][j] nodepre[j]=t
实验报告-最小生成树
一、问题描述
最小生成树是一副连通加权无向图中一棵权值最小的生成树。在一给定的无向图 G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即 ),而 w(u, v) 代表此边的权重,若存 在 T 为 E 的子集(即 )且 (V, T) 为树,使的 w(T) 最小,则此 T 为 G 的最小生成树。 最小生成树其实是最小权重生成树的简称。
end=j res.append([begin,end,min]) snode.append(end) cnode.remove(end) for j in res: j[0]=chr(j[0]+97) j[1]=chr(j[1]+97) return res max=99 row1=[0,5,11,5,max,max,max] row2=[5,0,max,3,9,max,7] row3=[11,max,0,7,max,6,max] row4=[5,3,7,0,max,max,20] row5=[max,9,max,max,0,max,8] row6=[max,max,6,max,max,0,8] row7=[max,7,max,20,8,8,0] map=[row1,row2,row3,row4,row5,row6,row7] graph=Graph(map) print("kruskal") print(graph.kruskal()) print("prim") print(graph.prim()) 代码二: inf=float('inf') def Dijkstra(nodes,edges,graph,start,end): nodepre=[0]*(nodes+1) #记录前驱 nodedis=[0]*(nodes+1) #记录节点遍历状态 dis=[inf for i in range(nodes+1)] #保存最短距离 road=[0]*(nodes+1) #保存最短路径 roads=[] map=graph for i in range(nodes+1):#初始化起点到其他点的距离 if i==start: dis[i]=0 else: dis[i]=map[start][i] if map[start][i]!=inf: nodepre[i]=start else: nodepre[i]=-1 nodedis[start]=1 for i in range(nodes+1):#每循环一次确定一条最短路 minn=inf for j in range(nodes+1):#寻找当前最短路
一个不带权图中若两点不相邻,邻接矩阵相应位置为 0,对带权图(网),相应位置为 ∞。一个图的邻接矩阵表示是唯一的,但其邻接表表示不唯一。在邻接表中,对图中每个顶 点建立一个单链表(并按建立的次序编号),第 i 个单链表中的结点表示依附于顶点 vi 的边 (对于有向图是以顶点 vi 为尾的弧)。每个结点由两个域组成:邻接点域(Adjvex),用以指 示与 vi 邻接的点在图中的位置,链域(Nextarc)用以指向依附于顶点 vi 的下一条边所对应 的结点。如果用邻接表存放网(带权图)的信息,则还需要在结点中增加一个存放权值的域 (Info)。每个顶点的单链表中结点的个数即为该顶点的出度(与该顶点连接的边的总数)。 无论是存储图或网,都需要在每个单链表前设一表头结点,这些表头结点的第一个域 data 用于存放结点 vi 的编号 i,第二个域 firstarc 用于指向链表中第一个结点。
return len(self.map) def edgenumber(self):
cnt=0 for i in range(self.nodenumber):
for j in range(i): if self.map[i][j]>0 and self.map[i][j]<99: cnt+=1
return cnt def kruskal(self):
for i in range(len(gp)): if edge[0] in gp[i]: m=i if edge[1] in gp[i]: n=i
if m!=n: res.append(edge) gp[m]=gp[m]+gp[n] gp[n] =[]
for j in res: j[0]=chr(j[0]+97) j[1]=chr(j[1]+97)