算法第十二期——BFS-判重

news2024/11/23 3:58:10

目录

BFS判重

Python判重方法: set、字典

set()判重

字典判重

 例题:跳蚱蜢

思路 

 【建模】

去重

代码一:字典去重(用list实现队列)

代码二:set()去重(用list实现队列)

代码二:set()去重(用deque实现队列) 推荐!


BFS判重

  • BFS=队列
  • BFS:逐步扩展下一层,把扩展出的下一层状态放进队列中处理。
  • 判重:若这些状态有相同的,只搜索一次,即进入队列一次,提高运行效率。

Python判重方法: set、字典

set()判重

  • set()函数创建一个无序、不重复元素集
  • 关系测试删除重复数据,计算交集、差集、并集、补集
# 对字符串去重
a = set ()
a.add("678"); print(a) # {'678'}
a.add("123"); print(a) # {'678', '123'}
a.add("678"); print(a) # {'678', '123'} 去重
b=sorted(a);  print(b) # ['123', '678'] sorted()返回的是列表
# 不能用sort(),因为sort()是list的方法

# 对单个字符串去重是对每个字母去重
s=set("aabc"); print(s)# {'a', 'c', 'b'}
print(len(s))          # 3       有多少种不同的字母
print(sorted(s))       # ['a', 'b', 'c'] 排序
# 对多个字符串去重是对每个字符串去重
s=set(["aabc","bca","aabc"]); print(s) # {'aabc', 'bca'}

# 对数字去重
b = set()
b.add(678) ; print(b)# {678}
b.add(123) ; print(b)# {123, 678}
b. add(678); print(b)# {123, 678}

a=set([1,1,2,3,5]); print(a) # {1, 2, 3, 5}
b=set([1,2,3,4]);print(b)    # {1, 2, 3, 4}
print(a-b)  # 差集,在集合a 中但不在集合b 中的元素  # {5}
print(b-a)  # 差集                             # {4}
print(a&b)  # 交集,同时在集合a和b中的共同元素。    # {1, 2, 3}
print (a|b) # 并集,包括集合a和b中所有元素。       # {1, 2, 3, 4, 5}
print(a^b)  # 补集,包括集合a和b的非共同元素。      # {4, 5}

字典判重

  • 字典:无序、可变、有索引的集合。
  • 字典:用花括号定义,有键和值。
print(a^b)  # 补集,包括集合a和b的非共同元素。      # {4, 5}
#%%
a={5:"xy"}
# 没有这个键就添加,有这个键就修改(相当于去重)
a[1]="cb"   # 添加键值对
a[2]="kd"
a[2]="af"   # 修改键值对
print(a)  # {5: 'xy', 1: 'cb', 2: 'af'}
b=sorted(a.items()) ; print(b)   # 按键排序[(1, 'cb'), (2, 'af'), (5, 'xy')]
b=sorted(a.values()) ; print(b)  # 值排序 ['af', 'cb', 'xy']
b=sorted(a.items(),key=lambda x: x[0]); print(b)  # 按键排序  [(1, 'cb'), (2, 'af'), (5, 'xy')]
b=sorted(a.items(),key=lambda x: x[1]); print(b)  # 按值排序  [(2, 'af'), (1, 'cb'), (5, 'xy')]

a={"food" :" xy" , " price" :555}
a[3]=899  # 键值对可以是不同类型
print(a)  # {'food': ' xy', ' price': 555, 3: 899}

 例题:跳蚱蜢

 跳蚱蜢2017年第八届省赛,lanqiao0J题号642

【题目描述】

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

如下图所示: 有 9 只盘子,排成 1 个圆圈。 其中 8 只盘子内装着 8 只蚱蜢,有一个是空盘。 我们把这些蚱蜢顺时针编号为 1 ~ 8。

每只蚱蜢都可以跳到相邻的空盘中, 也可以再用点力,越过一个相邻的蚱蜢跳到空盘中。

请你计算一下,如果要使得蚱蜢们的队形改为按照逆时针排列, 并且保持空盘的位置不变(也就是 1−8 换位,2−7换位,...),至少要经过多少次跳跃?

思路 

  • 从起始状态到终止状态,求最少跳跃次数
  • 最短路径问题
  • 用BFS

 【建模】

  • 直接让蚱蜢跳到空盘有点麻烦,因为有很多在跳蚱蜢。
  • 反过来看,让空盘跳,跳到蚱蜢的位置,简单多了,只有一个空盘在跳。

化圆为线

  • 题目是一个圆圈,不好处理,用一个建模技巧“化圆为线”,把圆形转换为线形。
  • 把空盘看成0,有9个数字{0,1,2,3,4,5,6,7,8},一个圆圈上的9个数字,拉直成了一条线上的9个数字,这条线的首尾两个数字0和8处理成相连的
  • 八数码问题:有9个数字{0,1,2,3,4,5,6,7,8},共有9!=362880种排列,不算多。

最短路径

  • 初始状态:“012345678”,目标状态:“087654321”。
  • 从初始状态“012345678”跳一次,有4种情况:0跳到1,2,7,8这几个点,即“1023456783"、“210345678”、“812345670”、“712345608"。
  • 然后从这4种状态继续跳到下一种状态,一直跳到目标状态为止,第一个出现的‘’087654321就是最短路径。
  • 用BFS扩展每一层。
  • 每一层就是蚱蜢跳了一次,扩展到某一层时发现终点“087654321”,这一层的深度就是蚱蜢跳跃的次数。

 第1步到第2步,有4种跳法;第2步到第3步,有4^2种;...;第20步,有4^20= 1万亿种,超时。

去重

判重:判断有没有重复跳,如果跳到一个曾经出现过的情况,就不用往下跳了。一共只有9!= 362880种情况。
代码复杂度:在每一层,能扩展出最少4种、最多362880种情况;若最后算出的答案是20层,那么最多算20*362880= 7,257,600次。在代码中统计实际的计算次数,是1451452次。
队列:最多有9!=362880种情况进入队列。

代码一:字典去重(用list实现队列)

  • list实现队列
  • 速度慢:3s,超时
def insertQueue(q: list, dir: int, news: tuple, vis):   #
    pos = news[1]               # 0的位置
    status = news[0]            # 当前状态
    insertPos = (pos + dir + 9) % 9  # 难点:化圆为线
    # 将字符串转为列表比较好处理
    t = list(status)
    t[pos], t[insertPos] = t[insertPos], t[pos]  # 空盘子与跳到的数交换
    # 处理完再转回字符串
    addStatus = "".join(t)
    # 去重
    if addStatus not in vis:    # 当前状态不在vis(没访问过)
        vis[addStatus] = 1      # 向字典vis添加,用去重作用
        q.append((addStatus, insertPos, news[2] + 1)) # 添加到队尾


q = [("012345678",0,0)]         # 到当前状态,空盘子0的位置,步数
vis = {"012345678": 1}          # 访问情况,用于去重
while q:                        # 队列不为空
    news = q.pop(0)             # 弹出队头
    if news[0] == "087654321":  # 结束条件:到达了目标状态,输出最少步数
        print(news[2])          # news[2]三元组第三个:步数。
        break
    #扩展下一层的4种情况
    insertQueue(q, -2, news,vis)   # 左边跳一个
    insertQueue(q, -1, news,vis)   # 左边跳两个
    insertQueue(q, 1, news, vis)   # 右边跳一个
    insertQueue(q, 2, news, vis)   # 右边跳两个

代码二:set()去重(用list实现队列)

用list实现队列

这个方法比上面简单一点。

# 与其他代码不同的地方已用注释标出
def insertQueue(q: list, dir: int, news: tuple, vis):   
    pos = news[1]
    status = news[0]
    insertPos = (pos + dir + 9) % 9
    t = list(status)
    t[pos], t[insertPos] = t[insertPos], t[pos]
    addStatus = "".join(t)
    if addStatus not in vis:
        vis.add(addStatus)      # 访问了就保存到vis
        q.append((addStatus, insertPos, news[2] + 1))


q = [("012345678",0,0)]
vis = set()           # vis访问情况。用set()去重
vis.add("012345678")  # 初始化第一个状态,存到vis
while q:
    news = q.pop(0)
    if news[0] == "087654321":
        print(news[2])
        break
    insertQueue(q, -2, news,vis)
    insertQueue(q, -1, news,vis)
    insertQueue(q, 1, news, vis)
    insertQueue(q, 2, news, vis)

代码二:set()去重(用deque实现队列) 推荐!

 用deque实现队列

 速度快:1.4s

# 与其他代码不同的地方已用注释标出
from collections import *  # 需导入collections
def insertQueue(q: list, dir: int, news: tuple, vis):
    pos = news[1]
    status = news[0]
    insertPos = (pos + dir + 9) % 9
    t = list(status)
    t[pos], t[insertPos] = t[insertPos], t[pos]
    addStatus = "".join(t)
    if addStatus not in vis:
        vis.add(addStatus)      # 访问了就保存到vis
        q.append((addStatus, insertPos, news[2] + 1))

q = deque()            # 用deque去重
q.append(("012345678",0,0))  # 初始化队列
vis = set()            # vis访问情况
vis.add("012345678")   # 初始化第一个状态,存到vis
while q:
    news = q.popleft() # 弹出队头
    if news[0] == "087654321":
        print(news[2])
        break
    insertQueue(q, -2, news,vis)
    insertQueue(q, -1, news,vis)
    insertQueue(q, 1, news, vis)
    insertQueue(q, 2, news, vis)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CRMEB开源商城部署在腾讯云2

目录PHP在安装过程中会监测Redish5跨域PHP在安装过程中会监测Redis public\install\index.php if (extension_loaded(redis)) {$redis <span class"correct_span">&radic;</span> 已安装;} else {$redis <a href"https://doc.crmeb.com/w…

2个大厂 100亿级 超大流量 红包 架构方案

2个大厂 100亿级 超大流量 红包 架构方案 文章目录2个大厂 100亿级 超大流量 红包 架构方案100亿级 红包 应用 场景概述百亿级 微信红包技术架构架构**南北分布****拆红包入账异步化****发拆落地&#xff0c;其他操作双层cache**高并发**红包算法****柔性降级方案**360w QPS 10…

Nginx与LUA(3)

您好&#xff0c;我是湘王&#xff0c;这是我的CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e;在互联网应用中&#xff0c;很多场景都会涉及到高并发请求&#xff0c;如果不对这些请求做限制&#xff0c;那么服务器很快就会被挤垮。就像在12306买票一样&…

计算机图形学实习教程之基本图形的生成(扫描线填充算法+图形缩放算法+对称变换算法+消隐算法+金刚石图案算法),利用C#实现,附源码

环境&#xff1a;Win10Visual Studio 2022 Community 在本次实验中需要用到第一篇文章实验内容的代码及环境&#xff0c;详情请见&#xff1a;传送门 目录 一、实验目的 二、实验步骤 1.扫描线填充算法 2.图形的缩放算法 3.对称变换算法 4.消隐算法 5.金刚石图形算法 一…

Unity 3D 人形角色动画(Avatar)||Unity 3D 导航系统||Unity 3D 障碍物

Unity 3D 人形角色动画&#xff08;Avatar&#xff09; Mecanim 动画系统适合人形角色动画的制作&#xff0c;人形骨架是在游戏中普遍采用的一种骨架结构。。 由于人形骨架在骨骼结构上的相似性&#xff0c;用户可以将动画效果从一个人形骨架映射到另一个人形骨架&#xff0c…

基于Java+SpringBoot+Vue求职招聘系统设计与实现

博主介绍&#xff1a;✌全网粉丝3W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供毕业项目实战✌ 博主作品&#xff1a;《微服务实战》专栏是本人的实战经验总结&#xff0c;《Spring家族及微服务系列》专注…

《Buildozer打包实战指南》第一节 在虚拟机中安装Ubuntu系统

目录 1.1 下载并安装Virtual Box虚拟机 1.2 下载并安装Ubuntu系统 由于Buildozer不能在Windows系统上打包&#xff0c;只能运行于Linux&#xff0c;所以我们可以在Windows系统上安装一个虚拟机&#xff0c;并在虚拟机中安装Linux。在本教程中笔者将会一直使用Ubuntu系统&…

大数据分案例-基于随机森林算法构建返乡人群预测模型

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

ubuntu16.04安装verilator+systemc并运行测试程序

link Verilator 能够把可综合的&#xff08;通常不是行为级&#xff09;的Verilog代码&#xff0c;外加一部分Synthesis&#xff0c;SystemVerilog和一小部分Verilog AMS代码转换成C或者SystemC代码。Verilator不是一个完整的模拟器&#xff08;simulator&#xff09;&#xff…

打工人必学的法律知识(六)——《劳动法》案例-差绩效不等于「不能胜任工作」

目录 一、差绩效不等于「不能胜任工作」 二、劳动者无条件解除劳动合同的情形 一、差绩效不等于「不能胜任工作」 员工在用人单位等级考核中居于末位等次&#xff0c;不等同于“不能胜任工作”&#xff08;最高人民法院指导案例18号&#xff09; 2005年7月&#xff0c;被告王…

【Linux】Linux多线程(上)

前言 hi~ 大家好呀&#xff0c;欢迎来到我的Linux学习笔记。本篇笔记将会重点从内核结构引入Linux下的线程&#xff0c;理解Linux下线程和进程的相关性和区别&#xff0c;以及线程相关的操作方法&#xff0c;在到之后的线程互斥和线程同步中的条件变量相关概念哦~ Linux进程控…

世界杯数据可视化分析

目录 1.数据来源 2.字段解释 世界杯成绩信息表&#xff1a;WorldCupsSummary 世界杯比赛比分汇总表&#xff1a;WorldCupMatches.csv 世界杯球员信息表&#xff1a;WorldCupPlayers.csv 3.数据分析及可视化 世界杯已经告一段落&#xff0c;作为一个学习大数据的学生&…

CentOS即将停止维护,拥抱阿里“龙蜥“(Anolis OS),VMware安装Anolis OS与介绍

一、前言 大家在自己电脑来进行服务器的一些操作时&#xff0c;基本都是使用CentOS 7或者是CentOS 8&#xff0c;但是2021年底CentOS 8宣布停止了维护&#xff1b;CentOS 7 在2024年6月30日也会停止维护&#xff01; 所以我们是时候换一个操作系统了&#xff0c;经过十几年的…

[319]. 灯泡开关

[319]. 灯泡开关题目算法设计&#xff1a;完全平方数题目 传送门&#xff1a;https://leetcode.cn/problems/bulb-switcher/ 算法设计&#xff1a;完全平方数 问题是有多少灯是亮的。 那怎么样灯才会亮呢&#xff1f; 点偶数次相当于没点&#xff0c;开了又关。只有点奇…

标准库中的string类

深爱学习的你&#xff0c;在很多场景下一定经常和字符串打交道&#xff01; 字符串是以‘\0’结尾的字符合集&#xff0c;C语言中提供了一些库函数来处理字符串,让大家在写代码的过程中方便了许多&#xff1a; 字符串函数_Bug程序员小张的博客-CSDN博客字符串函数https://blog…

基于Simulink的带通BPSK信号调制解调实验报告(含代码和slx文件)

重要声明:为防止爬虫和盗版贩卖,文章中的核心代码和数据集可凭【CSDN订阅截图或公z号付费截图】私信免费领取,一律不认其他渠道付费截图! 摘要 数字相位调制又称为相移键控(Phase Shift Keying,PSK),是一种十分重要的基本数字调制技术,是一种用载波相位表示输入信号…

磨金石教育摄影技能干货分享|有哪些风格独特的摄影作品

1 奋勇向前照片中退却的海浪与冲上岸的海浪交汇拍打&#xff0c;形成大量的白色泡沫。于是画面被平均分成两部分&#xff0c;分割线由左上延伸到右下&#xff0c;一条明显的对角线。也让画面形成对称式的构图&#xff0c;所以照片看着既平衡又美观。作者给照片起名为《奋勇向前…

Docker安装MySQL、MySQL主从复制、双主双从

文章目录Docker安装MySQL新建容器配置,记得 重启加载配置&#xff01;测试MySQL 主从复制原理新增两个mysql,一主一从在主机上在从机上MySQL双主双从必看&#xff01;创建容器在两个主机上在两个从机上问题解决Navicat无法连接MySQL的问题WARNING: IPv4 forwarding is disabled…

计算机网络概况

1 前言计算机网络是指将位于不同地理位置&#xff0c;但具有独立功能的多台设备&#xff0c;通过通信设备和线路连接起来&#xff0c;在网络操作系统&#xff0c;网络管理软件、网络通信协议的协调管理下&#xff0c;实现资源共享和信息传递的计算机系统。简单来说&#xff0c;…

智慧农业灌溉系统-数字农业-农业物联网机井灌溉节水新模式

平升电子智慧农业灌溉系统/农业物联网机井灌溉系统&#xff0c;可实现井电双控&#xff08;以电控水&#xff09;、以电折水、以阀控水等各种形式的地下取水井用水计量监测控制需求&#xff0c;助推农业水价改革实施、高效节水灌溉和地下水超采综合治理&#xff0c;促进节水型社…