三牛三虎过河问题--图的最短路径dijkstra算法--简单的Python实现
问题:三头牛三只虎要过河,船需要一只动物来划,另外至多还能载一物,而只有一头牛和一只虎会划船,并且当虎的数量多于牛的数量时,虎要吃牛,请设计一个安全渡河方案,并使渡河次数尽量少。
我们用一个数组来表示起点动物的状态,数组中元素为0表示此动物在起点,为1表示此动物不在起点(也就是在终点)
数组描述:[牛一, 牛二, 牛三,虎一,虎二,虎三]
例如:最开始时状态为 000000 (六只动物全部在起点)
结束状态:111111(六只动物全部到达终点)
那么这是一个求无权有向图的最短路径的问题,图的每个节点就是一个状态(此状态必须为有效状态),也就是说我们要从求起始节点(000000)到终点(111111)的路径
思路:
这是一个有向图,首先我们就要把这个图建出来,第一步就是找到所有节点(有效状态),我们定义一个find_all_valid_status函数来实现此功能:穷举法+判断是否合法(写一个judge_status_valid函数来实现),遍历000000->000001->000010->000011-> ··· ->111111,判断每个状态是否合法,如果合法就将此状态加入valid_status
第二,思考如何状态转移,由于只有一头牛和一头虎会划船,我们假设牛一和虎一会划船。于是定义一个状态转移数组translation,里面存储了11个合法转移方式,例如 100000表示牛一过河、 100100表示牛一和虎一过河、 001100表示牛三和虎一过河
然后如何通过这个状态转移数组来进行状态转移呢?这里使用异或运算,举个例子:
当前状态为100010, 起点:牛2,牛3 ,虎1,虎3 终点:牛1,虎2 我们要进行010100的状态转移(就是让牛2和虎1过河),那么就是 100010 ^ 010100 = 110110 起点:牛3,虎3 终点:牛1,牛2,虎1,虎2 这样是不是就成功让牛2和虎1过河了
我们知道了这个图的所有节点,并且知道了如何状态转移(就能求出这些节点之间的边),那么就能把这个图建出来。这里调用了Python的Graph库中的dijkstra,掩盖了dijkstra算法和建图的细节,写起来更简便
from dijkstar import Graph, find_path
import numpy as npnames = np.array(['牛一', '牛二', '牛三', '虎一', '虎二', '虎三'])
translation = [[1, 0, 0, 0, 0, 0],[1, 1, 0, 0, 0, 0],[1, 0, 1, 0, 0, 0],[1, 0, 0, 1, 0, 0],[1, 0, 0, 0, 1, 0],[1, 0, 0, 0, 0, 1],[0, 0, 0, 1, 0, 0],[0, 1, 0, 1, 0, 0],[0, 0, 1, 1, 0, 0],[0, 0, 0, 1, 1, 0],[0, 0, 0, 1, 0, 1]]
translation = np.array(translation)graph = Graph()
valid_status = []
def judge_status_valid(status)->bool: #判断一个状态是否合法cattles=0 //用来统计起点牛的数量tigers=0 //用来统计起点虎的数量for i in range(0, 3):if status[i] == 0:cattles += 1for i in range(3, 6):if status[i] == 0:tigers += 1if cattles == 3 or cattles == 0 or cattles == tigers: //根据起点虎和牛的数量来判断状态是否合法return Truereturn Falsedef find_all_valid_status():for i in range(0, 64): #相当于从000000遍历到111111status = bin(i)[2:] #这里是一个二进制字符串status = status.rjust(6, '0') #控制二进制位数为6位status = list(map(int, status)) #将字符串转换为列表global valid_statusif judge_status_valid(status):valid_status.append(status)valid_status = np.array(valid_status) #将有效状态的数组转换为numpy的数组类型def status_transfer(orgin_status, transfer_mode): #进行状态转移arr = []for i in range(len(orgin_status)):arr.append(orgin_status[i] ^ transfer_mode[i]) #异或运算得到下一个状态arr = np.array(arr)return arrdef build_graph():for status in valid_status:for transfer in translation:locations_1 = np.argwhere(transfer == 1).squeeze() #降维处理#print(locations_1)#print(type(locations_1))if locations_1.size==1 or status[locations_1[0]] == status[locations_1[1]]:next_status = status_transfer(status, transfer) #进行状态转移之后,下一个状态vertex1 = int(np.argwhere((valid_status==status).all(axis=1))) #查找status在valid_status中的位置,用位置索引作为图的顶点vertex2 = np.argwhere((valid_status==next_status).all(axis=1))if vertex2.size != 0:vertex2 = int(vertex2)#print("vertex=", vertex2, " ", vertex2.size)graph.add_edge(vertex1, vertex2, 1) #建立从顶点vertex1到vertex2的边,边长默认为1(每条边的边长为1,就相当于无权图了)def show_status(status): #根据当前状态数组打印出状态for i in range(status.size):if status[i] == 0:print(names[i], end="")print(" | ", end="");for i in range(status.size):if status[i] == 1:print(names[i], end="")def transfer_object(status1, status2):print(" 下一步转移对象:", end="");flag = 0for i in range(status1.size):if status1[i] != status2[i]:print(names[i], end=' ')flag = status1[i]if flag==0:print("从起点到终点", end=" ")else:print("从终点到起点", end=" ") def show_how_to_transfer(shortest_path): #打印转移过程for i in range(0, len(shortest_path)-1):#print(valid_status[path], type(valid_status[path]), valid_status[path].size)#根据当前状态和下一个状态确定转移对象path1 = valid_status[shortest_path[i]] #当前状态path2 = valid_status[shortest_path[i+1]] #下一个状态show_status(path1)transfer_object(path1, path2)print()show_status(valid_status[shortest_path[-1]])print()find_all_valid_status() #找到所有有效状态
build_graph() #建立图#一共有34个有效状态,那么就是求从起点0到终点33的最短路径
shortest_paths = find_path(graph, 0, 33) #用dijkstar算法求最短路径
print("最短路径:", shortest_paths.nodes)
show_how_to_transfer(shortest_paths.nodes)
三牛三虎过河问题--图的最短路径dijkstra算法--简单的Python实现相关推荐
- python棋盘最短路径_Python数据结构与算法之图的最短路径(Dijkstra算法)完整实例...
本文实例讲述了Python数据结构与算法之图的最短路径(Dijkstra算法).分享给大家供大家参考,具体如下: # coding:utf-8 # Dijkstra算法--通过边实现松弛 # 指定一个 ...
- 【数据结构】图(最短路径Dijkstra算法)的JAVA代码实现
最短路径的概念 最短路径的问题是比较典型的应用问题.在图中,确定了起始点和终点之后,一般情况下都可以有很多条路径来连接两者.而边或弧的权值最小的那一条路径就称为两点之间的最短路径,路径上的第一个顶点为 ...
- c++ 遍历所有点且距离最短_C/C++ 图的最短路径 Dijkstra 算法
作者:小石王 链接:https://www.cnblogs.com/xiaoshiwang/p/9442391.html 图的最短路径的概念: 一位旅客要从城市A到城市B,他希望选择一条途中中转次数最 ...
- 图的最短路径dijkstra算法
想法是这样的: 1. 最开始要建立4个list,分别存储 a. 所有的Vertex: allVertex[] b. 一个空的Vertex list: emptyVertex[] c. 一个前缀表 pr ...
- 遍历所有点的最短路径python_图遍历算法之最短路径Dijkstra算法
一.最短路径问题(shortest path problem) 最短路径问题是图论研究中一个经典算法问题,旨在寻找图中两节点或单个节点到其他节点之间的最短路径.根据问题的不同,算法的具体形式包括: 确 ...
- 有向无环图的最短路径求解算法
对于最短路径问题,Dijkstra算法只能求解所有边的权值都是非负的加权有向图,而Bellman-Ford算法虽然可以求解有负权值边的图的最短路径,但效率并不高.对于有向无环图,下面这种基于Dijks ...
- 【数据结构与算法】带权图最短路径Dijkstra算法
伪代码 //u是源节点 Initialization: N' = {u} for all nodes v if v is a neighbor of u then D(v) = c(u,v) e1se ...
- 图的最短路径--单源、多源最短路径
最短路径 –在网络中,求两个不同顶点之间的所有路径中,边的权值之和最小的路劲. 单源最短路径 –从某固定源点出发的最短路径 无权图的最短路径 按照路径长度递增的顺序找出源点到各个顶点的最短路径 类似于 ...
- 网络协议梳理(三)(网关和路由器、动态路由算法、Bellman-Ford算法、Dijkstra算法、动态路由协议、TCP和UDP)
MAC 头和 IP 头的细节 在任何一台机器上,当要访问另一个IP地址的时候,都会使用CIDR和子网掩码去判断目标IP地址和当前机器的IP地址是否属于同一网段. 如果是同一网段--如果ARP缓存中存有 ...
最新文章
- 用ASP.NET上传图片并生成带版权信息的缩略图
- 90. Leetcode 剑指 Offer 62. 圆圈中最后剩下的数字 (动态规划-基础题)
- android int与String的转换
- MySQL数据库备份工具mysqldump的使用(转)
- TURBOLinux 7.0下安装Oracle 8.1.7.0.1 release 3
- HaaS UI小程序
- AES加密算法256位密钥与128位密钥的不同之处
- 五、Kafka 用户日志上报实时统计之应用概述
- struts2如何使用拦截器进行用户权限控制
- java解析获得birt报表的数据_java pojo实体类做birt报表数据源
- sql查询数据库所有表(select * from sysobjects )
- JSP编程技术2-动态标签
- 计算机d盘无法格式化,电脑的D盘无法进行格式化怎么办?最强悍的三种解决方式看这里!...
- 黑客攻防与电脑安全-从新手到高手
- java解压zip和rar并解决乱码问题
- CCF CSP 中国计算机学会-CCF计算机软件能力认证(计算机水平测试)-简介-详情
- 信创办公--基于WPS的Word最佳实践系列(解决Word兼容性问题)
- Excel 解决高次方程求解的方法
- linux swp文件重启,Linux下.swp文件的恢复方法
- 【技巧分享】股票代码规则