算法导论实战(三)(算法导论习题第二十四章)

🌈 个人主页:十二月的猫-CSDN博客
🔥 系列专栏: 🏀算法启示录

💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光 

目录

前言

第二十四章 

24.1-3

24.1-4

24.2-4

24.3-2 

24.3-3

24.3-6

24.3-8

24.3-10 

总结


前言

算法导论的知识点学习将持续性更新在算法启示录_十二月的猫的博客-CSDN博客,欢迎大家订阅呀(反正是免费的哦~~)

实战篇也将在专栏上持续更新,主要目的是强化对理论的学习(题目来源:山东大学孔凡玉老师推荐)

第二十四章 

24.1-3

问题描述

假设给定G=(V,E)是一带权重且没有权重为负值的环路的有向图,对于所有的结点𝑣∈𝑉,从源结点s到结点v之间的最短路径中,包含边的条数的最大值为m。请对算法BELLMAN-FORD进行简单修改,可以让其在m+1遍松弛操作之后终止,即使m不是事先知道的一个数值。

问题分析:

如果一个图所有节点到源点s的距离包含的边的条数的最大值为m,那么意味算法在进行m轮松弛后,整个图的所有节点都已经得到最短路径。此时不再需要继续执行m+1轮松弛

问题求解
在BELLMAN-FORD算法的2-4行的执行记录下松弛前各点的最短路径长度,如果某一次松弛循环结束时所有v.d的值跟本次循环开始时v.d的值相比不发生改变时,此次循环即为第m+1次。 

INITALIZE-SINGLE-SOURCE(G,s)
for i=1 to |G.V|-1
  for each v in G.V
     save v.d to T
  for each edge(u,v) in G.E
     RELAX(u,v,w)
  for each v in G.V
    if v.d != T[v].d
     continue //没有点的值被更新,说明所有点都取到最短路径,则停止
  for each edge(u,v) in G.E
    if v.d>u.d+w(u,v)
      return FALSE
  return TRUE

24.1-4

问题描述:
修改Bellman-Ford算法,使其对于所有结点v来说,如果从源结点s都结点v的一条路径上存在权重为负值的环路,则将v.d的值设置为−∞。

问题分析:

贝尔曼福德算法不能够处理存在权重为负值的环路,因为一旦存在则会一直在环路上循环,因为这样的最短路径值会不停缩短。该情况显然是我们不希望发生的,所以我们增加这一个功能来应对存在负值环路的特殊情况。

问题求解:

如果存在负权环路,那么w(u,v)就是无穷小,并且w(s,v)(就是v.d)也是无穷小,于是这个if语句返回值是FLASE。所以只要在if内增加对v.d的修正即可

INITALIZE-SINGLE-SOURCE(G,s)
for i=1 to |G.V|-1
  for each v in G.V
     save v.d to T
  for each edge(u,v) in G.E
     RELAX(u,v,w)
  for each v in G.V
    if v.d != T[v].d
     continue //没有点的值被更新,说明所有点都取到最短路径,则停止
  for each edge(u,v) in G.E
    if v.d>u.d+w(u,v)
      v.d=-∞
      return FALSE
  return TRUE

24.2-4

问题描述:

给出一个有效的算法来计算一个有向无环图中的点的路径总数。分析你自己的算法。

问题分析:

目前我们手头关于图的知识点只有图的基本算法+最短路径算法+最小生成树,利用这些知识点来思考如何找路径总数。考虑到本题不用考虑有权图,所以我们把眼光转向BFS和DFS两个算法。进一步思考,我们能知道BFS常常用在求解最短路径算法中(BFS特点在于得到的是一棵树,同时每个点都是最短路径的),在这里我们需要求解的是到一个点的所有路径。

假如我们有如下一个图,现在要我们来求解顶点6的路径数

朴素想法:我们最朴素的想法就是从顶点1、2、3、5、4、....、这样的顺序去求解路径数。于是我们可以得到p(1)=1; p(2)+=p(1); p(3)+=p(1); p(5)+=p(2); p(4)+=p(2); 等等。

总的来说,就是从上层到下层计算,下层的路径数:下层路径数+=上层路径数

那什么是下层?什么又是上层呢?

下层:在上层结点撤去后不存在入度结点的点;上层:存在出度给其他顶点

如果可以从上层到下层计算呢?我们就需要对图进行拓扑排序


拓扑排序:是一种对有向图进行排序的算法,其主要目的是确定图中节点的线性顺序,使得在排序后,所有的边都从左到右指向更大的节点。换句话说,拓扑排序可以将图中的节点按照其依赖关系进行排序,使得所有的依赖关系都被满足。

 实现拓扑排序的方法有两个:一、计算结点入度+队列方法(通用方法)二、深度搜索(用于无环路的有向图

本题是有向无环图可以用方法二


问题求解:

一、利用DFS搜索树,将图进行拓扑排序,得到拓扑排序后的图

二、在新的图中,按照拓扑排序的顺序,对每个点u,找其所指向的点v,执行v.paths+=u.paths

PATHS(G)
    topologically sort the vertices of G
    for each vertex u, taken in topologically sorted order
        for each v ∈ G.Adj[u]
            v.paths = u.paths + v.paths
    return the sum of all paths attributes

24.3-2 

问题描述:

请举出一个包含负权重的有向图,使得 Dijkstra 算法在其上运行时将产生不正确的结果。为什么在有负权重的情况下,定理 24.6 的证明不能成立呢?

问题分析:

看到对本题的其中一个解答: 

大致意思是说:如果存在负权重回路,那么这个RELAX操作是没有意义的,因为RELEX是有限次的,但是通过负权重回路,我们到任何通过这个回路的点的距离都是−∞。于是在RELAX后,u.d并不是(s,u)的最小值,因此不成立

显然上面的证明是没有问题的,但是本题问的是为什么不能有负权重边,而不是负权重回路。所以仅仅有上面的证明是不充分的

问题求解:

Dijkstra算法是贪心贪心算法,也就是说每次都选择贪心策略下的局部最优解,这个解在后续中也不会再修正。那么对于如下的带有负权重的有向图:

假如源点是A,那么首先选择C此时C值为1;后选择B此时B的值为2,然后又会选择C此时C的值应该要修正为0.但是C的值不会被修正,因此Dijkstra每个点只访问一次(贪心策略)。所以最终C.d=1,但是实际上C到A的最小值为0。因此定理 24.6是不成立的,算法结束后,存在点的d的值不是最短路径值

24.3-3

问题描述:

假定将 Dijkstra 算法的第 行改为:

4 :white(lQl)>1

这种改变将让呻证循环的执行次数从 IVI 次降低到 IVI -1次。这样修改后的算法正确吗?

问题分析:

迪杰斯特拉算法最后得到的结果有两个:一、访问序列s,用来记录对点的访问次序;二、每个点的v.d记录每个点到源点的距离。

所以正确性的证明也将从这两个角度展开:

问题求解:

正确的!

一、假如我们已经得到前面V-1个点的访问序列,那么最后一个点不需要放入,我们也可以只知道最终的访问序列

二、迪杰斯特拉对每个结点只访问一次,且每次都能确定一个点的最短路径,此时程序运行了V-1个循环,访问并确定了V-1个点的最短路径。所以最后一个点进行松弛操作时,它并不能缩短其他点到原点的距离,所以最后一个点的RELAX操作也是无意义的。因此算法是正确的

24.3-6

问题描述:

问题分析: 

本题和最短路径问题存在几点不一样:

一、它需要找的是最可靠,也就是值最大的路径,可以认为是最长路径

二、最短路径算法相连路径段之间的关系是求和,但是通信链路相连路径段求可靠性时之间的关系是求积

问题求解:

一、最长路径。那就把贪婪准则改为选择d最大的点

二、总路径和子路径的关系变为乘。那就修改RELAX准则,从+变为*

三、初始化。源点可靠性为1;其他未搜索到的点初始化为0

INITIALIZE(G,s)
    for each vertex v ∈ G.V
        v.d=0
        v.π=NULL
    s.d=1
DIJKSTRA(G,w,s) //s用来记录访问的顺序,是需要返回的值;w边的权重集合
    S=空集合
    Q=G.V
    while(Q <> 空集合)
        u=EXTRACT-MAX(Q)
        S=S U {u}
        for each vertex v∈G.adj[u]
            RELEX(u,v,w) 
RELAX(u,v,w)
    if v.d<u.d*w(u,v)
        v.d=u.d*w(u,v)
        v.π=u

24.3-8

问题描述:

问题分析:

我第一次看这道题的时候,说实话,连题目都没看懂【emmmmm】。具体原因就在权重函数w:E->{0,1,...,W}这里没看明白。

这个权重函数就表示:边E的权重只能取{1,2,....,W}中的数

再来看看这个WV时间复杂度是哪里来的?要解决这个问题

先让友友们先思考另一个问题:WV含义是什么?

WV含义:图中任意点到源点的距离上限(图中任意点到源点的距离不超过WV)


再来思考一个这个E的时间复杂度含义又是什么?

E是指边,也就是说我需要对边进行E次操作,这不禁让我们想到了松弛操作。

E的复杂度就代表我们要对所有边进行一轮的松弛,每次松弛边本质是更新点的V.d,所以本质就是对点进行了E次的操作

问题求解:

从优化“贪心寻找dist最小点”的操作入手。由于边权≤W≤𝑊,那么一个点的dist值不会超过VW。基于这个条件,我们可以抽象出一个长度为VW的队列数组。每个数组的队列存储着“dist值为该数组序号”的点。然后抽象出一个指针,这个指针指向的队列,是我们贪心取点的队列。由于一个点被取出后,被他更新的点只会被push进该队列或者该队列之后的队列,所以指针只会从左到右扫描一遍数组。

最多扫描一遍数组,复杂度为O(VW)。此外,最多会有E次入队、出队操作,复杂度为O(E)。总时间复杂度为O(VW+E)。

#include <bits/stdc++.h>
#define mp make_pair
using namespace std;
const int N = ..., M = ..., W = ...;
queue<int> qs[N*W];
int head[N], ver[M], edge[M], Next[M], tot = 0;//采用数组模拟邻接链表的方式
void add(int x,int y,int z){
  ver[++tot] = y, edge[tot] = z, Next[tot] = head[x], head[x] = tot;
}
int d[N], v[N];
int n, m, w;
void dijkstra(int s){
  memset(d,0x3f,sizeof(d));//初始化为正无穷
  memset(v,0,sizeof(v));
  d[s] = 0; qs[0].push(s);
  for(int k = 0; k<=n*w; k++){
    while(!qs[k].empty()){
      int x = qs[k].front(); qs[k].pop();
      if(v[x]) continue;
      v[x] = 1;
      for(int i = head[x]; i; i = Next[i]){
        int y = ver[i], z = edge[i];
        if(d[y] > d[x] + z){
          d[y] = d[x] + z;
          qs[d[y]].push(y);
        }
      }
    }
  }
}

24.3-10 

问题描述:

假设给定带权重的有向图 G=(V, E), 从源结点s发出的边的权重可以为负值,而其他所有边的权重全部是非负值,同时,图中不包含权重为负值的环路。证明: Dijkstra 算法可以正确计算出从源结点到所有其他结点之间的最短路径。 

问题分析:

证明Dijkstra 算法是可行的==证明一个贪心策略是有效的。考虑到Dijkstra 算法本身的贪心策略已经证明结束,所以我们只需要针对其中变化的部分进行特别论证即可

特别部分:从源结点s发出的边的权重可以为负值

利用 Dijkstra 算法取出S,并更新与S相邻的点,将得到多个值不为0的点

于是,该问题可以等效为:多源点且初始值不为0的最短路径问题,并且每个源点都可以适用Dijkstra 算法

因此,整个问题同样可以利用 Dijkstra 算法来求解

问题求解:

首先,Dijkstra的算法思路是:对于任意一个从队列取出来的点x,如果它没有被标记过,那么d[x]一定是源结点s到x的最短路径,然后我们不断地进行贪心扩展,最终可以得到源结点s到每个结点的最短路径。它的本质是一个贪心+BFS算法。
现在,题目中给出的限制是:“只有从源结点s出发的边权重可以为负,且图中无负环”。
源结点s一定是在一开始被取出,更新完之后被丢弃。因为只有源结点s出发的边权重可以为负,所以我们在后面更新由“s以外的其他点”更新“s以外的其他点”时,仍旧是在一个无负边权的图中的更新,所以Dijkstra仍正确。而对于这些点,当他们尝试更新s的时候,因为图中无负环,所以无法更新s。此外,由于无负环,s也不会出现有一个权值为负的子环无限更新自身的情况。综上,Dijkstra基于贪心的性质没有发生改变,每次从队列中取出的一个点更新完其他点被丢弃后,这个点在后面一定不会被更新。所以Dijkstra仍旧可以正确运行。

总结

本文到这里就结束啦~~

本篇文章的撰写花了本喵四个多小时

如果仍有不够,希望大家多多包涵~~

如果觉得对你有帮助,辛苦友友点个赞哦~

知识来源:《算法导论》课后习题、山东大学孔凡玉老师ppt。不要用于商业用途转发~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/688583.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【TB作品】MSP430G2553单片机,MSP430 单片机读取 SHT30 传感器并显示数据

使用 MSP430 单片机读取 SHT30 传感器并显示数据 作品功能 本文介绍了如何使用 MSP430 单片机读取 SHT30 温湿度传感器的数据&#xff0c;并通过 OLED 屏幕显示实时的温度和湿度信息。通过此项目&#xff0c;您将学习如何配置 MSP430 的 I2C 接口、读取 SHT30 传感器的数据以…

Linux 中常用的设置、工具和操作

1.设置固定的ip地址步骤 1.1 添加IPADDR“所设置的固定ip地址” TYPE"Ethernet" PROXY_METHOD"none" BROWSER_ONLY"no" BOOTPROTO"static" DEFROUTE"yes" IPV4_FAILURE_FATAL"no" IPV6INIT"yes" IPV6…

【Vue】作用域插槽

插槽分类 默认插槽&#xff1a;组件内定制一处结构 具名插槽&#xff1a;组件内定制多处结构 插槽只有两种&#xff0c;作用域插槽不属于插槽的一种分类。作用域插槽只是插槽的一个传参语法 作用&#xff1a; 定义slot 插槽的同时, 是可以传值的。给 插槽 上可以 绑定数据&a…

SOA主要协议和规范

Web服务作为实现SOA中服务的最主要手段。首先来了解Web Service相关的标准。它们大多以“WS-”作为名字的前缀&#xff0c;所以统称“WS-*”。Web服务最基本的协议包括UDDI、WSDL和SOAP&#xff0c;通过它们&#xff0c;可以提供直接而又简单的Web Service支持&#xff0c;如图…

外部mysql导入

利用这个命令&#xff1a; mysql -u username -p database_name < file.sql 然后就这样。成功导入。

Rocky Linux安装与基础配置

目录 背景与起源 主要特点 目标用户 发展前景 下载 安装 常用配置命令&#xff1a; 更换镜像源 Rocky Linux 是一个开源的、由社区驱动的操作系统&#xff0c;旨在使用 Red Hat Enterprise Linux&#xff08;RHEL&#xff09;源码构建的下游二进制兼容发行版。以下是关于…

vue3 监听器,组合式API的watch用法

watch函数 在组合式 API 中&#xff0c;我们可以使用 watch 函数在每次响应式状态发生变化时触发回调函数 watch(ref,callback&#xff08;newValue,oldValue&#xff09;&#xff0c;option:{}) ref:被监听的响应式量&#xff0c;可以是一个 ref (包括计算属性)、一个响应式…

Linux Mint 默认禁用未经验证的 Flatpak 软件包

Linux Mint 默认禁用未经验证的 Flatpak 软件包 Linux Mint 新政策 Linux Mint 项目宣布了一项新政策&#xff0c;即默认禁用那些未经官方验证的 Flatpak 软件包&#xff0c;以增强用户的安全保障。 当用户选择启用未经验证的 Flatpak 软件包时&#xff0c;Linux Mint 的软…

ceph radosgw 原有zone placement信息丢失数据恢复

概述 近期遇到一个故障环境&#xff0c;因为某些原因&#xff0c;导致集群原有zone、zonegroup等信息丢失&#xff08;osd&#xff0c;pool等状态均健康&#xff09;。原有桶和数据无法访问&#xff0c;经过一些列fix后修复&#xff0c; 记录过程 恢复realm和pool相关信息 重…

二轴机器人大米装箱机:技术创新引领智能包装新潮流

在科技日新月异的今天&#xff0c;自动化和智能化已成为各行各业追求高效、精准生产的关键。作为粮食加工行业的重要一环&#xff0c;大米装箱机的技术创新与应用价值日益凸显。其中&#xff0c;二轴机器人大米装箱机以其高效、稳定、智能的特点&#xff0c;成为市场的新宠。星…

删除目录

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 删除目录可以通过使用os模块提供的rmdir()函数实现。通过rmdir()函数删除目录时&#xff0c;只有当要删除的目录为空时才起作用。rmdir()函数的基本语…

【STL源码剖析】priority_queue 优先队列的简单实现

水到绝处是风景 人到绝境是重生 目录 priority_queue的模拟实现 源码剖析&#xff1a; 代码测试&#xff1a; 契子✨ 我们之前不仅讲过 队列queue 还有 双端队列deque 而我们今天所讲的依旧是队列家族的成员 -- 优先队列priority_queue 顾名思义&#xff0c;priority_queue是…

网络实用技术答案

&#xff08; C &#xff09;不属于计算机网络四要素。A. 计算机系统 B. 传输介质C. 用户 D. 网络协议计算机网络中广域网和局域网的分类是以&#xff08; D &#xff09;来划分的。A. 信息交换方式 B&#xff0e;传输控制方法C. 网络使用习惯 D&#xff0e;网络覆盖范围计算机…

蓝桥云课第12届强者挑战赛

第一题&#xff1a;字符串加法 其实本质上就是一个高精度问题&#xff0c;可以使用同余定理的推论 &#xff08;ab&#xff09;%n((a%n)(b%n))%n; #include <iostream> using namespace std; const int mod1e97; int main() {string a,b;cin>>a>>b;ab;int …

CorelDRAW2024最新版本有哪些功能?揭秘设计界最新神器!

“设计”一词最早来源于拉丁语“designare”&#xff0c;意为计划&#xff0c;构思。随着时代的发展&#xff0c;人们将“设计”理解为一种创造性活动&#xff0c;通过这种活动&#xff0c;人们可以创造出新的产品、新的场景以及新的体验。 「CorelDRAW汉化版下载」&#xff0c…

Spring Boot框架基础

文章目录 1 Spring Boot概述2 Spring Boot入门2.1 项目搭建2.2 入门程序 3 数据请求与响应3.1 数据请求3.2 数据响应 4 分层解耦4.1 三层架构4.2 控制反转4.3 依赖注入 5 参考资料 1 Spring Boot概述 Spring是Java EE编程领域的一个轻量级开源框架&#xff0c;是为了解决企业级…

AI日报|文生语音大模型国内外均有突破,Pika完成6亿新融资,视频大模型也不远了!

文章推荐 AI搜索哪家强&#xff1f;16款产品实战测评&#xff0c;效率飙升秘籍&#xff01; AI日报&#xff5c;智谱AI再降价&#xff0c;同时开源9B系列模型&#xff1b;国内外气象大模型竞逐升级 字节推出文本到语音模型家族Seed-TTS&#xff1a;擅长情感表达&#xff0c;…

前端 JS 经典:打印对象的 bug

1. 问题 相信这个 console 打印语句的 bug&#xff0c;其实小伙伴们是遇到过的&#xff0c;就是你有一个对象&#xff0c;通过 console&#xff0c;打印一次&#xff0c;然后经过一些处理&#xff0c;再通过 console 打印&#xff0c;发现两次打印的结果是一样的&#xff0c;第…

定个小目标之每天刷LeetCode热题(12)

这是一道简单题&#xff0c;使用位运算中的异或运算即可&#xff0c;异或运算有以下性质&#xff1a; 1、任何数异或 0 结果仍然是原来的数&#xff0c;即 a⊕0a 2、任何数和其自身做异或运算&#xff0c;结果是 0 所以我们只需要让数组里的所有元素进行异或运算得到的结果就…

30、matlab现代滤波:维纳滤波/LMS算法滤波/小波变换滤波

1、信号1和信号2的维纳滤波 实现代码 N 2000; %采样点数 Fs 2000; %采样频率 t 0:1 / Fs:1 - 1 / Fs; %时间序列 Signal1 sin(2*pi*20* t) sin(2*pi*40* t) sin(2*pi*60* t); Signal2[2*ones(1,50),zeros(1,50),-1*ones(1,100),zeros(1,50),-2*ones(1,50),zeros(1,50),1…