当前位置:   article > 正文

算法导论24-26、34-35章_算法导论34章答案

算法导论34章答案

单源最短路

问题描述:
给定带权重的有向图G=(V,E)和权重函数w,能够将每条边映射到实数值得权重上。
给定一个源点,希望求出它到所有节点的最小权重路径。

定义路径的权重
该路径上所有边的权重之和
在这里插入图片描述

定义最短路径权重
在这里插入图片描述

最短路径问题具有最优子结构
最短路径子路径也是最短路径
本质上还是反证法的思想
在这里插入图片描述
负权重的边
1.Bellman-Ford算法允许图中有负权环;并且能够检测负权回路的存在
2.Dijkstra算法要求边非负。

环路
1、最短路径不能包含权重为负值的环——否则最短路径可能会导致-∞
2、最短路径不能包含权重为正值的环——如果包含这样的环,那么我们删掉这个环,可以得到一个更小的最短路径
因此,最短路径中没有环路,是简单路径。
因此,一条最短路径最多包含V个结点,|V|-1条边。

展示最短路
需要为每个结点维持一个前驱结点Π,Π=NIL或为另一个结点。
由此,我们可以定义出 V π 和 E π V_\pi和E_\pi VπEπ:
在这里插入图片描述
G π G_\pi Gπ是一棵最短路径树,包含了从源节点s到每个可以到的顶点的一条最短路径。
最短路径不一定是唯一的,最短路径树也不一定是唯一的。

松弛操作:
为每个结点维持另一个属性d,用来记录从s到该结点的最短路径权重的上界,称d为最短路径估计。
松弛:唯一导致最短路径估计d和前驱节点 π \pi π发生变化的操作
在这里插入图片描述
Dijkstra:对每条边仅松弛
Bellman-Ford:每条边松弛|V|-1次

初始化
为所有结点初始化d和 π \pi π两个属性:
在这里插入图片描述

一些性质
在这里插入图片描述



Bellman-Ford算法

允许权重为负值的边
通过对边进行松弛操作降低所有顶点的最短路径估计d,并更新 π \pi π值,直到d=最短路径权重。
除此之外,算法会返回一个布尔值来表明图中是否存在负权环。

BELLMAN-FORD(G,w,s)
	INITIALIZE-SINGLE-SOURCE(G,s)
	for i = 1 to G.|V|-1	//因此最短路径的长度至多为|V|-1
		for each edge (u,v) ∈ G.E
			RELAX(u,v,w)
	for each edge(u,v) ∈ G.E	//检测负权环
		if v.d > u.d + w(u,v)
			return FALSE
	return TRUE
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

T ( n ) = Θ ( V ) + Θ ( E ( V − 1 ) ) + O ( E ) = O ( V ⋅ E ) T(n)=\Theta(V)+\Theta(E(V-1))+O(E)=O(V·E) T(n)=Θ(V)+Θ(E(V1))+O(E)=O(VE)



DAG算法

先对有向无环图进行拓扑排序,确定每个结点之间的一个线性次序。如果有u到v的一条边,那u的次序在v前面。
我们只需要按照拓扑排序对结点进行一遍处理,每次对一个节点进行处理时,对该结点发出的所有边进行松弛操作

DAG-SHORTEST-PATHS(G,w,s)
1	topologically sort the vertices of G
2	INITIALIZE-SINGLE-SOURCE(G,s)
3	for each vertex u,taken in topologically sorted order
4		for each vertex v that u adjacent to	//可以建立一个邻接数组,adj[u]
5			RELAX(u,v,w)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

时间复杂度:
在这里插入图片描述



Dijkstra算法

要求所有边权重非负。
每次选择一个“最短”的路径——贪心算法

DIJKSTRA(G,w,s)
	INITIALIZE-SINGLE-SOURCE(G,s)	//初始化
	S = 空集
	Q = G.V		//始终满足Q=V-S
	While Q != 空集
		u = EXTRACT-MIN(Q)	//u是未加入结点中最小最短路估计
		S = S ∪ {u}
		//如果经过u的路径使s到v更短,则更新v的属性
		for each vertex v ∈ G.adj[u]
			RELAX(u,v,w)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Dijkstra算法的实现依赖于最小优先队列
1.利用编号结点来维持最小优先队列:EXTRACT-MIN需要 O ( V ) O(V) O(V),搜索整个数组, T ( n ) = O ( V 2 + E ) = O ( V 2 ) T(n)=O(V^2+E) = O(V^2) T(n)=O(V2+E)=O(V2)
2.使用斐波那契堆实现最小优先队列:
EXTRACT-MIN需要 O ( l g V ) O(lgV) O(lgV) T ( n ) = O ( V l g V + E ) T(n)=O(VlgV+E) T(n)=O(VlgV+E)



所有结点最短路

不再给出源点,需要求所有结点对之间的最短路径,实际上就是|V|次单源最短路,但这样做效率很低。

为了求出问题,不仅需要计算最短路权重,还需要计算出前驱结点矩阵 Π = ( π i j ) \Pi=(\pi_{ij}) Π=(πij) π i j \pi_{ij} πij在i=j或不存在i到j路径时为NIL,否则给出的是从i到j的最短路上j的前驱结点。

同样,我们可以定义一个最短路径树 G π , i G_{\pi,i} Gπ,i,只是这里多了一个参数–我们需要给出根节点i:

PRINT-ALL-PAIRS-SHORTEST-PATH(Π,i,j)
	if i == j
		print i
	elseif Π_ij == NIL
		print "no path from i to j exists"
	else PRINT-ALL-PAIRS-SHORTEST-PATH(Π,i,Π_ij)
	print j
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

下面给出三种解决方法
1、基于矩阵乘法的动态规划算法—— Θ ( V 3 l g V ) \Theta(V^3lgV) Θ(V3lgV)
2、Floyd-Warshll算法(动态规划)—— Θ ( V 3 ) \Theta(V^3) Θ(V3)
3、Johnson算法—— O ( V 2 l g V + V E ) O(V^2lgV+VE) O(V2lgV+VE)

基于矩阵乘法的动态规划

定义 l i j ( m ) l_{ij}^{(m)} lij(m)表示从i到j至多包含m条边的任意路径的最小权重
m = 0 m=0 m=0,在这里插入图片描述
m ≥ 1 m\ge1 m1在这里插入图片描述
我们考虑图中不含负权环,而最短路最多n-1条边,因此 最小路径权重 = l i j ( n − 1 ) = l i j ( n ) = l i j ( n + 1 ) = . . . 最小路径权重=l_{ij}^{(n-1)}=l_{ij}^{(n)}=l_{ij}^{(n+1)}=... 最小路径权重=lij(n1)=lij(n)=lij(n+1)=...

输入矩阵 W i , j = ( w i j ) W_{i,j}=(w_{ij}) Wi,j=(wij),且 L ( 1 ) = W L^{(1)}=W L(1)=W
通过对最短路径一条边一条边的扩展来计算最短路权重。

EXTENDED-SHORTEST-PATHS(L,W)
	n = L.rows
	let L' = (l_ij') be a new n*n matrix
	for i = 1 to n
		for j = 1 to no
			l_ij' =for k =1 to n
				l_ij' = min(l_ij',l_k+w_kj)
	return L'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

返回矩阵L’=(l_ij’)
T ( n ) = Θ ( n 3 ) T(n)=\Theta(n^3) T(n)=Θ(n3)

SLOW-ALL-PAIRS-SHORTEST-PATHS(W)
	n = W.rows
	L(1) = W
	for m = 2 to n-1
		Let L(m) be a new n*n  matrix
		L(m) =  EXTENDED-SHOERTEST-PATH(L(m-1),W)
	return L(n-1)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这样算 T ( n ) = Θ ( n 4 ) T(n)=\Theta(n^4) T(n)=Θ(n4)
我们考虑改进算法
由我们刚刚推导出的 最小路径权重 = l i j ( n − 1 ) = l i j ( n ) = l i j ( n + 1 ) = . . . 最小路径权重=l_{ij}^{(n-1)}=l_{ij}^{(n)}=l_{ij}^{(n+1)}=... 最小路径权重=lij(n1)=lij(n)=lij(n+1)=...,我们可以采用重复平方技术来减小时间复杂度:
在这里插入图片描述

FASTER-ALL-PAIRS-SHORTEST-PATHS(W)
	n = W.rows
	L(1) = W
	m = 1
	while m <= n
		Let L(2m) be a new n*n matrix
		L(2m) = EXTENDED-SHORTEST-PATHS(L(m),L(m))
	return L(m)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

最后的结果 L ( m ) = L ( n − 1 ) L^{(m)} = L^{(n-1)} L(m)=L(n1)
一共计算了lg(n-1)取上整个矩阵,每个矩阵时间为 Θ ( n 3 ) \Theta(n^3) Θ(n3),因此 T ( n ) = Θ ( n 3 l g n ) T(n)=\Theta(n^3lgn) T(n)=Θ(n3lgn)


Floyd-Warshall算法

允许负权重的边存在。
动态规划算法。

d i j ( k ) d_{ij}^{(k)} dij(k)为从结点i到j的所有中间结点全部取自{1,2,…,k}的一条最短路的权重。
在这里插入图片描述

FLOYD-WARSHALL(W)
	n = W.rows
	D(0) = W
	for k = 1 to n
		let D(k) = (d_ji^k)be a new n*n matrix
		for i = 1 to n
			for j = 1 to n
				d_ij^k = min(d_ij^(k-1),d_ik^(k-1)+d_kj^(k-1))
	return D(n)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

三层循环 T ( n ) = Θ ( n 3 ) T(n) = \Theta(n^3) T(n)=Θ(n3)

这里只返回了权重矩阵,仍需构建一条最短路,需要构建前驱矩阵
1、先计算权重矩阵D,从D构造前驱矩阵 Π \Pi Π,再用PRINT-ALL-PAIRS-SHORTEST-PATH打印最短路径, T ( n ) = O ( n 3 ) T(n)=O(n^3) T(n)=O(n3)
2、计算 D ( k ) D^{(k)} D(k)的同时计算前驱矩阵 Π \Pi Π,定义 Π = Π ( n ) 且 Π i j ( k ) \Pi=\Pi^{(n)}且\Pi_{ij}^{(k)} Π=Π(n)Πij(k)为从i到j的一条所有中间结点取自{1,2,…,k}的最短路径上j的前驱节点
在这里插入图片描述
传递闭包
定义:传递闭包为图 G ∗ = ( V , E ∗ ) G^*=(V,E^*) G=(V,E),其中 E ∗ = i , j :如果图 G 中有一条 i 到 j 的路径 E^*={i,j:如果图G中有一条i到j的路径} E=ij:如果图G中有一条ij的路径

我们定义 t i j ( k ) = 1 t_{ij}^{(k)}=1 tij(k)=1代表图G中存在一条从i到j的路径,其中间结点均属于{1,2,…,k}中,否则 = 0 =0 =0.那么传递闭包 G ∗ = ( V , E ∗ ) G^*=(V,E^*) G=(V,E):将边(i,j)置于 E ∗ 中    ⟺    t i j ( j ) = 1 E^*中\iff t_{ij}^{(j)}=1 Etij(j)=1
在这里插入图片描述

TRANSITIVE-CLOSURE(G)
	n = |G.V|
	let T(0) = (t_ij^0) be a new n*n matrix
	for i = 1 to n
		for j = 1 to n
			if i==j or (i,j)∈E
				t_ij^0 = 1
			else t_ij^0 = 0
	for k = 1 to n
		let T(K) = (t_ij^k) be a new n*n matrix
		for i = 1 to n
			for j = 1 to n
				t_ij^k = t_ij^(k-1) ∨ (t_ik^(k-1) ∧ t_kj^(k-1)return T(n)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

T ( n ) = Θ ( n 3 ) T(n) = \Theta(n^3) T(n)=Θ(n3)
最后得到的结果实际上是个可达矩阵,因为得到的路径它中间能够包含所有结点。若第i行第j列为1,就代表着存在着从i至j的一条路径。

稀疏图Johnson算法

在这个算法中使用到了Dijkstra算法和Bellman-Ford算法:
1、它会返回包含所有结点对的最短路径权重的矩阵;
2、并报告输入图中是否存在负权环路

Johnson算法为边重新赋予权重
如果图G中所有边权重非负,可以通过对每个结点运行一次Dijkstra算法解决问题;若使用斐波那契堆最小优先队列, T ( n ) = O ( V 2 l g V + V E ) T(n)=O(V^2lgV+VE) T(n)=O(V2lgV+VE);
如果G中有负权重边,但没有负权环路,那么只要计算出一组新的非负权重值,然后使用Dijkstra算法。新赋予的权重 u ^ \hat{u} u^必须满足两个性质:
1、不改变最短路径的性质
2、新权重非负
在这里插入图片描述

JOHNSON(G,w)
  • 1

在这里插入图片描述

在这里插入图片描述
若使用斐波那契堆实现Dijkstra中的最小优先队列,算法 T ( n ) = O ( V 2 l g V + V E ) T(n)=O(V^2lgV+VE) T(n)=O(V2lgV+VE)
若使用二叉最小堆, T ( n ) = O ( V E l g V ) T(n)=O(VElgV) T(n)=O(VElgV)



最大流

流网络G=(V,E)是一个有向图,每条边有一个非负容量值 c ( u , v ) ≥ 0 c(u,v)\ge0 c(u,v)0,并且若E中有边(u,v),则不含其反向边(v,u).
流网络中有一个源节点s,汇点t。若对于每个结点来说,都有一条从s经过v到t的路径,那我们说流网络是流通的。
除s外,每个结点都至少有一条进入边,因此 ∣ E ∣ ≥ ∣ V ∣ − 1 |E|\ge |V|-1 EV1

流:满足性质:容量限制 & 流量守恒

容量限制:对所有结点v,要求流的大小不超过容量大小
流量守恒:对所有除s、t之外的结点,要求从结点流出的总流量=流入结点的总流量和

流的大小
从源点流出的总流量-流入源点的总流量
在这里插入图片描述

Fold-Fulkerson算法

关键思想:残存网络、增广路径、切割

构建残存网络,寻找一条增广路径,修改流的值,在残存图中添加反向边;循环此过程直到找不到增广路径为止。

总的来看,每次迭代都会增加流的值,但对于G中的一条特定来说,其流量可能增加也可能减少,这是因为对某些边缩减是有必要的,这可能会让更多的流从源点发送到汇点。

这种算法能够获得一个最大流

一、残存网络

残存网络:
定义一条边可以允许额外流量=该边容量-该边上的流量,称之为残存容量
在这里插入图片描述
残存网络 G f = ( V , E f ) , E f = ( u , v ) ∈ V ∗ V : c f ( u , v ) > 0 G_f=(V,E_f),E^f ={ (u,v)∈V*V:c_f(u,v)>0 } Gf=(V,Ef),Ef=(u,v)VV:cf(u,v)>0,也就是说残存网络中的每条边或残存边都必须允许大于0的流量通过; E f E_f Ef中的边要么是E中所有边,要么是其反向边,因此有 ∣ E f ∣ ≤ 2 ∣ E ∣ |E_f|\le 2|E| Ef2∣E

需要厘清,残存网络并不是流网络,因为他不满足流网络的定义——他可能包含边(u,v)及其反向边(v,u)。
除此之外,它具有和流网络同样的性质。

二、增广路径

增广路径:
残存网络中一条从源点s到汇点t的简单路径。
每条这样的路径它的流量值决定于路径上所有边的最小残存容量。在这里插入图片描述

三、切割

流网络中的一个切割(S,T)将V划分为S和T两个集合,T=V-S,且源点s∈S,汇点t∈T。

若f是一个流,则定义横跨切割(S,T)的净流量f为:从集合S中流出的总流量-流入集合S的总流量在这里插入图片描述
切割(S,T)的容量是从集合S到集合T所有路径的总容量在这里插入图片描述

我们只关注最小切割——整个网络中容量最小的切割

对于给定的流f,横跨任何切割的净流量都相同,都等于|f|

流网络中,任意流f的值都不能超过任意切割的容量

最大流最小割定理
在这里插入图片描述

FOLD-FULKERSON-METHOD(G,s,t)
	for each edge(u,v)∈G.E
		(u,v).f = 0	//初始化流f=0
	while there exists a path p from s to t in the residual network Gf
		c_f(p) = min {c_f(u,v):(u,v) is in p}	//找到路径p的瓶颈值
		for each edge (u,v) in p
			//对流进行更新,若残存边是G中边,则加流量,否则减流量
			if (u,v)E
				(u,v).f = (u,v).f + c_f(p)
			else (v,u).f = (v,u).f - c_f(p)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

运行时间取决于如何寻找增广路径
如果使用深度优先/广度优先搜索,在残存网络中找到一条路径的时间应是 O ( V + E ′ ) = O ( E ) O(V+E') = O(E) O(V+E)=O(E),因此while每一遍执行所需O(E),而while最多循环次数是 ∣ f ∗ ∣ |f^*| f次,所以 T ( n ) = O ( E ∣ f ∗ ∣ ) T(n)=O(E|f^*|) T(n=O(Ef)



Edmonds-Karp算法

改变FOLD-FULKERSON算法,使要找的增广路径为从s到t的最短路径,其中每条边的权重为单位距离。
这样,算法时间为 O ( V E 2 ) O(VE^2) O(VE2)

最大二分匹配

使用FOLD-FULKERSON 算法能在 O ( V E ) O(VE) O(VE)时间内解决图G=(V,E)的最大二分匹配问题。

二分图:在这里插入图片描述
构建一个流网络,其中流对应匹配。
我们设源节点s和汇点t是不属于结点集V的新节点,并且V’=V ∪ {s,t}
在这里插入图片描述
|M|——二分图中能匹配的最多结点对个数
利用FOLD算法在G’中找到一条最大流f,那么G中就存在一个匹配M,满足|M| = |f|



P与NP

基础定义:P、NP、NPC

下面主要是一些常见的NPC问题。
电路可满足性问题——第一个证明的NPC问题。
在这里插入图片描述

团问题CLIQUE

寻找图中规模最大的团的最优化问题。
实际上就是找图G中最大的完全子图。

证明团问题是NPC问题:证明 3 − C N F − S A T ≤ p C L I Q U E 3-CNF-SAT\le_p CLIQUE 3CNFSATpCLIQUE

顶点覆盖问题VERTEX COVER

给出一个图G,找到一个最小的顶点集合,使其能够覆盖G中每条边

证明顶点覆盖问题是NPC问题:证明 C L I Q U E ≤ p V E R T E X − C O V E R CLIQUE\le_p VERTEX-COVER CLIQUEpVERTEXCOVER

哈密顿回路问题HAM-CYCLE

给出一个图G,找出一条回路,使其能够恰经过所有顶点仅1次。

证明哈密顿回路是NPC问题:证明 V E R T E X − C O V E R T ≤ p H A M − C Y C L E VERTEX-COVERT\le_p HAM-CYCLE VERTEXCOVERTpHAMCYCLE

旅行商问题TSP

经过哈密顿回路,恰好访问每个城市一次,并回到出发城市。
除此之外,要求费用最小——每条路的权重之和

证明旅行商问题是NPC问题:证明 H A M − C Y C L E ≤ p T S P HAM-CYCLE\le_p TSP HAMCYCLEpTSP

子集和问题SUBSET-SUM

给出一个有限正整数集合S和一个整数目标t>0,找到一个字集合,使其所有元素和恰好为t。

证明子集和问题是NPC问题:证明 3 − C N F − S A T ≤ p S U B S E T − S U M 3-CNF-SAT\le_p SUBSET-SUM 3CNFSATpSUBSETSUM

所有证明过程在此处省略。



近似算法

近似算法:返回近似最优解的算法
  • 1

近似比:

  • 最大化问题:满足 0 < C ≤ C ∗ 0\lt C \leq C^* 0<CC,比值 C ∗ / C C^*/C C/C表示最优解代价大于近似解代价的倍数。
  • 最小化问题:满足 0 < C ∗ ≤ C 0\lt C^* \leq C 0<CC,比值 C / C ∗ C/C^* C/C表示近似解代价大于最优解代价的倍数。
  • 算法的近似比不会小于1
  • 一个1近似算法产生的解就是最优解;而一个近似比较大的近似算法可能会返回和最优解差很多的解

一些NPC问题可以采用特定的多项式时间近似算法求解,通过消耗更多的计算时间来得到不断缩小的近似比;另一些问题,在已知的最佳多项式时间近似算法中,近似比是输入规模n的函数,随着n的变化而变化。

  • 一个最优化问题的近似模式approximation scheme就是近似算法:
    • 输入除了问题的实例外,还有一个值 ϵ > 0 \epsilon > 0 ϵ>0,使得对于任何固定 ϵ \epsilon ϵ,该模式是一个 ( 1 + ϵ ) (1+\epsilon) (1+ϵ)近似算法。

    • 对一个近似模式来说,如果对任何固定的 ϵ > 0 \epsilon > 0 ϵ>0,该模式都以输入实例规模n的多项式时间运行,则称此模式为多项式时间近似模式

    • 随着 ϵ \epsilon ϵ的减小,多项式时间近似模式的运行时间可能会迅速增长在这里插入图片描述

    • 完全多项式时间近似模式在这里插入图片描述
      下面给出一些NPC问题的近似算法。

顶点覆盖问题

规模不超过 最优顶点覆盖规模2倍的顶点覆盖

在这里插入图片描述
例:
在这里插入图片描述
邻接表来表示E,算法的运行时间为 O ( V + E ) O(V+E) O(V+E)

旅行商问题

满足三角不等式:
两地之间直接到达的代价最小
在这里插入图片描述
我们考虑满足三角不等式的旅行商问题,近似算法代价不超过最优的2

在这里插入图片描述
例:
在这里插入图片描述

一般旅行商问题,即没有满足三角不等式的假设,那么问题就无法在多项式时间内找到一个好的近似算法,除非P=NP

集合覆盖问题set-cover

给出一个有穷集X,和它的一个子集族,每个元素至少在一个子集中,我们希望找到一个最小数量的子集集合,使其能覆盖X中所有元素。

贪心近似算法:
在这里插入图片描述
在这里插入图片描述
近似比是 l n ∣ X ∣ + 1 ln|X|+1 lnX+1

带权顶点覆盖问题

在顶点覆盖问题中,每个顶点都具有一个正权值,希望找出一个具有最小权的顶点覆盖

利用线性规划松弛,构造近似解
在这里插入图片描述
该算法是一个近似比为2的近似算法

子集和问题

指数时间的近似算法
在这里插入图片描述
完全多项式时间近似模式
在这里插入图片描述
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/243648
推荐阅读
相关标签
  

闽ICP备14008679号