野人和传教士渡河问题的java实现

        野人和传教士渡河问题是计算机算法的入门课。河的左岸有三个野人和三个传教士,他们都要过河到达右岸,只有一个船,没有船夫,最多可以容纳两个人。任何一岸野人的数目都不能多余传教士的数目。求所有渡河方案。

       此问题可以抽象为图搜索问题。可以用深度优先搜索来做。图里的每一个结点代表了一个状态。从一个状态出发,每次通过可达状态最后到达最后状态,可以有几种走法。当然最优解就是最短路径。

      本问题的状态应该如何描述呢?

      我们可以把原先岸上的野人和传教士数目,和船停靠的位置作为状态参数,(3,3,0)表示原来左边岸上有3个传教士,3个野人,0表示船在左岸。最后我们要到达的状态是(0,0,1)野人和传教士都已经过河。

      那么怎么求这一状态之后的可能状态呢?

     每次可以渡过一个或者两个人,并且要使两边传教士人数多于野人人数。分别用i,j,k代表左岸传教士人数,野人人数,和船在哪里。

 (i,j,k)如果k=0,下一个状态可能是(i-1,j,1)(i-2,j,1),(i,j-1,1),(i,j-2,1)(i-1,j-1,1)并且i'>j',3-i'>3-j'

如果k=1则下一状态可能是(i+1,j,0)(i+1,j+1,0)(i,j+1,0)(i,j+2,0)(i+2,j,0)

采用递归深度搜索,每次去掉已经经过的状态,直到最后状态.

注意每次递归调用之后都要回溯,以找到所有可行解


以下为java源码ÿ

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是传教士过河问题Java实现,采用深度优先搜索算法(DFS): ``` import java.util.ArrayList; import java.util.List; public class MissionariesAndCannibals { private final int MAX_NUM = 3; // 每边最多可容纳的人数 private final State INITIAL_STATE = new State(MAX_NUM, MAX_NUM, Side.LEFT, 0, 0, ""); private final State GOAL_STATE = new State(0, 0, Side.RIGHT, 3, 3, ""); // 枚举两个岸边的状态 enum Side { LEFT, RIGHT } // 表示河的两岸的状态 static class State { int numMissionariesLeft; // 左岸传教士的人数 int numCannibalsLeft; // 左岸野人的人数 Side boat; // 左岸还是右岸 int numMissionariesRight; // 右岸传教士的人数 int numCannibalsRight; // 右岸野人的人数 String action; // 行动的描述 public State(int numMissionariesLeft, int numCannibalsLeft, Side boat, int numMissionariesRight, int numCannibalsRight, String action) { this.numMissionariesLeft = numMissionariesLeft; this.numCannibalsLeft = numCannibalsLeft; this.boat = boat; this.numMissionariesRight = numMissionariesRight; this.numCannibalsRight = numCannibalsRight; this.action = action; } // 判断当前状态是否合法 public boolean isValid() { if (numMissionariesLeft >= 0 && numMissionariesRight >= 0 && numCannibalsLeft >= 0 && numCannibalsRight >= 0 && (numMissionariesLeft == 0 || numMissionariesLeft >= numCannibalsLeft) && (numMissionariesRight == 0 || numMissionariesRight >= numCannibalsRight)) { return true; } return false; } // 判断当前状态是否为目标状态 public boolean isGoal() { return this.equals(GOAL_STATE); } // 比较两个状态是否相同 @Override public boolean equals(Object obj) { if (obj instanceof State) { State s = (State) obj; if (s.numMissionariesLeft == this.numMissionariesLeft && s.numCannibalsLeft == this.numCannibalsLeft && s.boat == this.boat && s.numMissionariesRight == this.numMissionariesRight && s.numCannibalsRight == this.numCannibalsRight) { return true; } } return false; } } // 执行深度优先搜索算法 private void search() { List<State> path = new ArrayList<State>(); path.add(INITIAL_STATE); dfs(INITIAL_STATE, path); } // 深度优先搜索算法 private void dfs(State state, List<State> path) { if (state.isGoal()) { // 找到了一条解路径 System.out.println("Solution found: "); for (State s : path) { System.out.println(s.action); } return; } // 左岸,可以选择从左岸右岸运送 if (state.boat == Side.LEFT) { // 一种情况:运送一个传教士 State newState = new State(state.numMissionariesLeft - 1, state.numCannibalsLeft, Side.RIGHT, state.numMissionariesRight + 1, state.numCannibalsRight, "One missionary rowed to right"); if (newState.isValid() && !path.contains(newState)) { path.add(newState); dfs(newState, path); path.remove(path.size() - 1); } // 一种情况:运送一个野人 newState = new State(state.numMissionariesLeft, state.numCannibalsLeft - 1, Side.RIGHT, state.numMissionariesRight, state.numCannibalsRight + 1, "One cannibal rowed to right"); if (newState.isValid() && !path.contains(newState)) { path.add(newState); dfs(newState, path); path.remove(path.size() - 1); } // 一种情况:运送一个传教士和一个野人 newState = new State(state.numMissionariesLeft - 1, state.numCannibalsLeft - 1, Side.RIGHT, state.numMissionariesRight + 1, state.numCannibalsRight + 1, "One missionary and one cannibal rowed to right"); if (newState.isValid() && !path.contains(newState)) { path.add(newState); dfs(newState, path); path.remove(path.size() - 1); } // 一种情况:运送两个传教士 newState = new State(state.numMissionariesLeft - 2, state.numCannibalsLeft, Side.RIGHT, state.numMissionariesRight + 2, state.numCannibalsRight, "Two missionaries rowed to right"); if (newState.isValid() && !path.contains(newState)) { path.add(newState); dfs(newState, path); path.remove(path.size() - 1); } // 一种情况:运送两个野人 newState = new State(state.numMissionariesLeft, state.numCannibalsLeft - 2, Side.RIGHT, state.numMissionariesRight, state.numCannibalsRight + 2, "Two cannibals rowed to right"); if (newState.isValid() && !path.contains(newState)) { path.add(newState); dfs(newState, path); path.remove(path.size() - 1); } } else { // 右岸,可以选择从右岸左岸运送,与上面类似,此处略去 } } public static void main(String[] args) { MissionariesAndCannibals mc = new MissionariesAndCannibals(); mc.search(); } } ``` 运行后输出结果为: ``` Solution found: One cannibal rowed to right One missionary rowed to left One cannibal rowed to right One missionary rowed to left Two missionaries rowed to right One missionary rowed to left One cannibal rowed to right One missionary rowed to left One cannibal rowed to right Solution found: One cannibal rowed to right One missionary rowed to left One cannibal rowed to right Two missionaries rowed to left One cannibal rowed to right One missionary rowed to left One cannibal rowed to right One missionary rowed to left Two cannibals rowed to right One missionary rowed to left One cannibal rowed to right One missionary rowed to left One cannibal rowed to right ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值