问题:三头牛三只虎要过河,船需要一只动物来划,另外至多还能载一物,而只有一头牛和一只虎会划船,并且当虎的数量多于牛的数量时,虎要吃牛,请设计一个安全渡河方案,并使渡河次数尽量少。

我们用一个数组来表示起点动物的状态,数组中元素为0表示此动物在起点,为1表示此动物不在起点(也就是在终点)

数组描述:[牛一, 牛二, 牛三,虎一,虎二,虎三]

例如:最开始时状态为 000000 (六只动物全部在起点)

结束状态:111111(六只动物全部到达终点)

那么这是一个求无权有向图的最短路径的问题,图的每个节点就是一个状态(此状态必须为有效状态),也就是说我们要从求起始节点(000000)到终点(111111)的路径

思路:

  1. 这是一个有向图,首先我们就要把这个图建出来,第一步就是找到所有节点(有效状态),我们定义一个find_all_valid_status函数来实现此功能:穷举法+判断是否合法(写一个judge_status_valid函数来实现),遍历000000->000001->000010->000011-> ··· ->111111,判断每个状态是否合法,如果合法就将此状态加入valid_status

  2. 第二,思考如何状态转移,由于只有一头牛和一头虎会划船,我们假设牛一和虎一会划船。于是定义一个状态转移数组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过河了
    
  3. 我们知道了这个图的所有节点,并且知道了如何状态转移(就能求出这些节点之间的边),那么就能把这个图建出来。这里调用了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实现相关推荐

  1. python棋盘最短路径_Python数据结构与算法之图的最短路径(Dijkstra算法)完整实例...

    本文实例讲述了Python数据结构与算法之图的最短路径(Dijkstra算法).分享给大家供大家参考,具体如下: # coding:utf-8 # Dijkstra算法--通过边实现松弛 # 指定一个 ...

  2. 【数据结构】图(最短路径Dijkstra算法)的JAVA代码实现

    最短路径的概念 最短路径的问题是比较典型的应用问题.在图中,确定了起始点和终点之后,一般情况下都可以有很多条路径来连接两者.而边或弧的权值最小的那一条路径就称为两点之间的最短路径,路径上的第一个顶点为 ...

  3. c++ 遍历所有点且距离最短_C/C++ 图的最短路径 Dijkstra 算法

    作者:小石王 链接:https://www.cnblogs.com/xiaoshiwang/p/9442391.html 图的最短路径的概念: 一位旅客要从城市A到城市B,他希望选择一条途中中转次数最 ...

  4. 图的最短路径dijkstra算法

    想法是这样的: 1. 最开始要建立4个list,分别存储 a. 所有的Vertex: allVertex[] b. 一个空的Vertex list: emptyVertex[] c. 一个前缀表 pr ...

  5. 遍历所有点的最短路径python_图遍历算法之最短路径Dijkstra算法

    一.最短路径问题(shortest path problem) 最短路径问题是图论研究中一个经典算法问题,旨在寻找图中两节点或单个节点到其他节点之间的最短路径.根据问题的不同,算法的具体形式包括: 确 ...

  6. 有向无环图的最短路径求解算法

    对于最短路径问题,Dijkstra算法只能求解所有边的权值都是非负的加权有向图,而Bellman-Ford算法虽然可以求解有负权值边的图的最短路径,但效率并不高.对于有向无环图,下面这种基于Dijks ...

  7. 【数据结构与算法】带权图最短路径Dijkstra算法

    伪代码 //u是源节点 Initialization: N' = {u} for all nodes v if v is a neighbor of u then D(v) = c(u,v) e1se ...

  8. 图的最短路径--单源、多源最短路径

    最短路径 –在网络中,求两个不同顶点之间的所有路径中,边的权值之和最小的路劲. 单源最短路径 –从某固定源点出发的最短路径 无权图的最短路径 按照路径长度递增的顺序找出源点到各个顶点的最短路径 类似于 ...

  9. 网络协议梳理(三)(网关和路由器、动态路由算法、Bellman-Ford算法、Dijkstra算法、动态路由协议、TCP和UDP)

    MAC 头和 IP 头的细节 在任何一台机器上,当要访问另一个IP地址的时候,都会使用CIDR和子网掩码去判断目标IP地址和当前机器的IP地址是否属于同一网段. 如果是同一网段--如果ARP缓存中存有 ...

最新文章

  1. 用ASP.NET上传图片并生成带版权信息的缩略图
  2. 90. Leetcode 剑指 Offer 62. 圆圈中最后剩下的数字 (动态规划-基础题)
  3. android int与String的转换
  4. MySQL数据库备份工具mysqldump的使用(转)
  5. TURBOLinux 7.0下安装Oracle 8.1.7.0.1 release 3
  6. HaaS UI小程序
  7. AES加密算法256位密钥与128位密钥的不同之处
  8. 五、Kafka 用户日志上报实时统计之应用概述
  9. struts2如何使用拦截器进行用户权限控制
  10. java解析获得birt报表的数据_java pojo实体类做birt报表数据源
  11. sql查询数据库所有表(select * from sysobjects )
  12. JSP编程技术2-动态标签
  13. 计算机d盘无法格式化,电脑的D盘无法进行格式化怎么办?最强悍的三种解决方式看这里!...
  14. 黑客攻防与电脑安全-从新手到高手
  15. java解压zip和rar并解决乱码问题
  16. CCF CSP 中国计算机学会-CCF计算机软件能力认证(计算机水平测试)-简介-详情
  17. 信创办公--基于WPS的Word最佳实践系列(解决Word兼容性问题)
  18. Excel 解决高次方程求解的方法
  19. linux swp文件重启,Linux下.swp文件的恢复方法
  20. 【技巧分享】股票代码规则

热门文章

  1. Xilinx ZynqMP相关
  2. ie6浏览器下border边框线出现断裂问题解决方法
  3. 正则表达式详解(三、常用符号的使用)
  4. 注册DLL文件命令的使用方法详细说明
  5. Python鼠标连续点击事件
  6. 永澄:认知层次模型-道术器用
  7. 【正则表达式大全-固定格式字符】
  8. 想做好物流成本控制,得秉承这个思路
  9. 关于oracle数据库死锁的解决 以及产生的原因
  10. 三国杀服务器改名 插图修改,三国杀7年前老版灵雎焚心到底多恶心?换身份让官方被迫修改...