ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: 香川群子

[讨论] 出个算法题,大家练练手【3个和尚和3个妖怪过河】

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2018-9-12 22:52 | 显示全部楼层
从这个数据结构开始,船的位置,和尚数,妖怪数可以直接赋值。但是下一个场景呢,我们需要计算得出来。代码如下:
Option Explicit

Public Type scence
    scence_description As String
    next_scence As String
End Type

Function get_next_scence(scence_description)
Dim result, i As Long, j As Long, boat_location, left_bank_monks, left_bank_monsters, right_bank_monks, right_bank_monsters


    result = Split(scence_description, "-")
    boat_location = result(0)
    left_bank_monks = result(1)
    left_bank_monsters = result(2)
    right_bank_monks = 3 - left_bank_monks
    right_bank_monsters = 3 - left_bank_monsters
    result = ""


    If boat_location = "left" Then
        For i = 0 To left_bank_monks
            For j = 0 To left_bank_monsters
                If i + j > 0 And i + j <= 2 Then
                    If is_monks_safe(left_bank_monks - i, left_bank_monsters - j, right_bank_monks + i, right_bank_monsters + j) Then
                        result = result & "right-" & left_bank_monks - i & "-" & left_bank_monsters - j & ","
                    End If
                End If
            Next j
        Next i
    End If
   
    If boat_location = "right" Then
        For i = 0 To right_bank_monks
            For j = 0 To right_bank_monsters
                If i + j > 0 And i + j <= 2 Then
                    If is_monks_safe(left_bank_monks + i, left_bank_monsters + j, right_bank_monks - i, right_bank_monsters - j) Then
                        result = result & "left-" & left_bank_monks + i & "-" & left_bank_monsters + j & ","
                    End If
                End If
            Next j
        Next i
    End If
   
    result = Left(result, Len(result) - 1)
   
    get_next_scence = result
   
End Function

Function is_monks_safe(left_bank_monks, left_bank_monsters, right_bank_monks, right_bank_monsters)
    is_monks_safe = (left_bank_monks = 0 Or left_bank_monks >= left_bank_monsters) And (right_bank_monks = 0 Or right_bank_monks >= right_bank_monsters)
End Function

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-9-13 08:39 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 香川群子 于 2018-9-13 09:00 编辑
yipzx 发表于 2018-9-12 22:52
从这个数据结构开始,船的位置,和尚数,妖怪数可以直接赋值。但是下一个场景呢,我们需要计算得出来。代码 ...

嗯。你的函数,已经可以根据现在状态,计算出下一个可能状态。
left-3-3right-3-2,right-3-1,right-2-2

接下来,还是需要进行广度遍历,然后适当剪枝,才能得到最短有效路径吧。

TA的精华主题

TA的得分主题

发表于 2018-9-13 10:43 来自手机 | 显示全部楼层
本帖最后由 yipzx 于 2018-9-13 22:56 编辑

手机不好打字,附件也不好传,大家将就看一下。
下面是广度搜索。配合题意写复杂了一点。
result 是需要求的结果。这个结果可能不止一个,所以他是个集合。同时,我们考虑,如果第一个场景无解,我们需要将他的下一个场景加入判断,同时删除无解的第一个场景。还有一条广度搜索重要的条件,就是不能回到以前去过的场景,不然就无限循环了。这个需要好好体会一下,香老师之前有写。
没有用type数据结构,在昨天的函数的基础上直接给一个答案。不理解的地方,大家提出来即可。


Option Explicit
Public gMONKS As Long
Public gMONSTERS  As Long

Sub main()
    Dim result As New Dictionary
    Dim key
    Dim i As Long
    Dim is_done As Boolean
    Dim next_scene
   
    gMONKS = 4
    gMONSTERS = 4
    result.Add "left-" & gMONKS & "-" & gMONSTERS, False
    is_done = False
   
    Do Until (result.Count = 0 Or is_done = True)
   
        For Each key In result.Keys' 保证广度全遍历,一般广度搜索只求最短路径,这是此题特别的地方
            If last_scene(key) = "right-0-0" Then
                result(key) = True
                is_done = True
            End If
        Next key
   
        If Not is_done Then
            For Each key In result.Keys
                next_scene = get_next_scene(last_scene(key))
                For i = LBound(next_scene) To UBound(next_scene)
                    If InStr(1, key, next_scene(i)) = 0 Then' 不能重复
                        result.Add key & "," & next_scene(i), False
                    End If
                Next i
                result.Remove key
            Next key
        End If
        
    Loop
   
    If result.Count = 0 Then Debug.Print "No result!"
    For Each key In result.Keys
        If result(key) Then
            Debug.Print key
        End If
    Next key
   
End Sub

Function last_scene(key)
    Dim tmp
    tmp = Split(key, ",")
    tmp = tmp(UBound(tmp))
    last_scene = tmp
End Function


Function get_next_scene(scene)
Dim result, i As Long, j As Long, boat_location, left_bank_monks, left_bank_monsters, right_bank_monks, right_bank_monsters


    result = Split(scene, "-")
    boat_location = result(0)
    left_bank_monks = result(1)
    left_bank_monsters = result(2)
    right_bank_monks = gMONKS - left_bank_monks
    right_bank_monsters = gMONSTERS - left_bank_monsters
    result = ""


    If boat_location = "left" Then
        For i = 0 To left_bank_monks
            For j = 0 To left_bank_monsters
                If i + j > 0 And i + j <= 2 Then
                    If is_monks_safe(left_bank_monks - i, left_bank_monsters - j, right_bank_monks + i, right_bank_monsters + j) Then
                        result = result & "right-" & left_bank_monks - i & "-" & left_bank_monsters - j & ","
                    End If
                End If
            Next j
        Next i
    End If
   
    If boat_location = "right" Then
        For i = 0 To right_bank_monks
            For j = 0 To right_bank_monsters
                If i + j > 0 And i + j <= 2 Then
                    If is_monks_safe(left_bank_monks + i, left_bank_monsters + j, right_bank_monks - i, right_bank_monsters - j) Then
                        result = result & "left-" & left_bank_monks + i & "-" & left_bank_monsters + j & ","
                    End If
                End If
            Next j
        Next i
    End If
   
    result = Left(result, Len(result) - 1)
   
    get_next_scene = Split(result, ",")
   
End Function

Function is_monks_safe(left_bank_monks, left_bank_monsters, right_bank_monks, right_bank_monsters)
    is_monks_safe = (left_bank_monks = 0 Or left_bank_monks >= left_bank_monsters) And (right_bank_monks = 0 Or right_bank_monks >= right_bank_monsters)
End Function




TA的精华主题

TA的得分主题

发表于 2018-9-25 06:37 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2018-9-28 11:09 | 显示全部楼层
呵呵呵,这个问题有意思,研究一下。向楼主学习

TA的精华主题

TA的得分主题

发表于 2018-9-28 16:26 | 显示全部楼层
本帖最后由 zyuhai119 于 2018-9-28 16:45 编辑
ykqrs 发表于 2018-9-4 14:47
第一步:两个妖过去,下一个妖,留一个妖开船返回,3-1;1;0-1
第二步:再上一个妖,下一个妖,留一个妖 ...

返回也算一个步骤

思维模式共需7步 以左岸到右岸
1.输入       左岸:3人 1妖         右岸:1妖(1妖在船上)
2.返回       左岸:3人2妖          右岸:1妖
3.输入       左岸:2人1妖          右岸:1人1妖   (1妖在船上)
4.返回       左岸:2人2妖          右岸:1人1妖
5.输入       左岸:1人1妖          右岸:2人1妖   (1妖在船上)
6.返回       左岸:0人2妖          右岸:3人1妖   
7.输入       左岸:0人0妖          右岸:3人3妖     

以算法过程拆分看
假设 A为人  B为妖     
任意步骤下要同时满足以下条件:
左侧 A>=B        过程A>=B  or A  or B      右侧 A>=B

这样理解不知道对不对

TA的精华主题

TA的得分主题

发表于 2018-9-29 08:39 | 显示全部楼层
呵呵呵,不知道这里的
5.输入       左岸:1人1妖          右岸:2人1妖   (1妖在船上)
6.返回       左岸:0人2妖          右岸:3人1妖   

这个步骤中,从5返回1妖的时候,左岸加船上共2妖1人算不算不合理(呵呵),此时应该是返回的妖先不上岸,人上船后再让妖上岸才行吧。

TA的精华主题

TA的得分主题

发表于 2018-9-29 08:57 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
ljpmqb888 发表于 2018-9-29 08:39
呵呵呵,不知道这里的
5.输入       左岸:1人1妖          右岸:2人1妖   (1妖在船上)
6.返回        ...

和尚 m=3 ,妖怪 n=3 时 ,可能的所有状态有 16+16=32种。

1、A列代表 船在出发点时 ,出发点的 “和尚+妖怪” 数量,16种状态;
2、首行代表 船在出发点对岸时 ,出发点的 “和尚+妖怪” 数量,也是16种状态。

qq12.jpg

考虑 妖怪吃和尚规则,要求
If (i - j >= 0 And i - j <= m - n) Or i Mod m = 0 Then '和尚大于等于妖怪
筛选后,合理合法的状态 剩下10+10=20 种, 如下图

qq44.JPG

不同状态之间的路径 用“1” 做了标记,是根据乘船规则制定的
If x2 >= 0 And x1 <= 2 - x2 Then '乘船规则

TA的精华主题

TA的得分主题

发表于 2018-9-29 09:02 | 显示全部楼层
zopey 发表于 2018-9-29 08:57
和尚 m=3 ,妖怪 n=3 时 ,可能的所有状态有 16+16=32种。

1、A列代表 船在出发点时 ,出发点的 “和 ...

哦,这个很明确了,我再想想,表面看这个问题好像很简单,可是实际操作起来还真不简单,有很多细节需要考虑全面。研究这个算法能开阔思路啊!!谢谢老师指点!!

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-9-29 15:12 | 显示全部楼层
ljpmqb888 发表于 2018-9-29 08:39
呵呵呵,不知道这里的
5.输入       左岸:1人1妖          右岸:2人1妖   (1妖在船上)
6.返回        ...

规则要求任何时候(场合,即左岸、右岸、船上)都确保和尚数大于妖怪数。

这是可以做到的,并且这也是难点。否则就太容易了。
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

关闭

最新热点上一条 /1 下一条

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-6-17 17:13 , Processed in 0.047669 second(s), 7 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表