题干

  1. 要从 A岸 出发到 B岸,A岸有 M 只羊、N 只狼和 1 个农夫,船每一趟可载 X 只动物。
  2. 有农夫看着、或则羊的数量大于狼,羊就不会被吃。
  3. 请返回任一躺数最少方案。

题解

题目可转化为:在一个有向无路长的图中,在不知道各个节点之间如何连接的基础上,找到两个节点之间的最短路径。

数据结构

public class Pack {
    public int sheep; // 羊的数量
    public int wolf;  // 狼的数量
    public int farmer;// 农夫的数量
}

public class Node {
    public static HashSet<Node> s_finded;  // 已经探索过的所有结点

    public Pack   landA; // A岸的情况
    public Pack   landB; // B岸的情况
    public Node[] gotos; // 连接的结点
    public Node   from;  // 来自结点
    
    // 探索该节点能够前往的节点;返回是否探索到终点
    public bool explore(int boatCarry); 
    // 将结点添加到 Node.s_finded 中 
    public void finded();  
    // 将结点添加到自己的 gotos 中;将结点的 from 设置为自己
    public void markGoto(Node node); 
}

算法

采用 bfs 广度优先算法来求最短路径,搭配剪枝来确保低计算复杂度:

  1. queue.Enqueue(起点)
  2. while(!queue.isEmpty)

    1. node = queue.Dequeue()
    2. node.explore(boatCarry) | boatCarry 是船的最大运载值

      1. this.find()
      2. 遍历所有支持的运载方案,对于运载方案指向的结点 goto:

        1. 羊+狼 超过最大运载 -> Continue
        2. 发现过 -> Continue
        3. 为终点

          1. goto.find()
          2. this.markGoto(goto)
          3. return true
        4. 不安全

          1. goto.find()
          2. Continue
        5. 安全 -> goto.find();this.markGoto(goto);goto入队

解题历程

一开始还不确定题目和图论相关,按照直接思路,构建了面向对象的相关方案,分别定义了类:岸、船、船渡。模拟对应的解题方案过程中,逐渐确认题型。

经过分析

  • 两个状态:开始状态、目标状态
  • 可剪枝:当状态下的某岸的 狼 大于等于 羊,该状态可剪
  • 状态流转:船渡

题目建模
在一个有向无路长的图中,在不知道各个节点之间如何连接的基础上,找到两个节点之间的最短路径。

继续优化

  • 从两个节点互相对外进行 BFS 搜索,猜测这样 时间复杂度会减半。

RDDcoding
151 声望17 粉丝

一心一行