三个怪兽和三个和尚过河java版
2016-12-19 19:41
239 查看
三个怪兽和三个和尚过河java版
三个怪兽和三个和尚过河java版简介
代码
Appjava
ItemStatejava
ActionEnumjava
BoatDirectionEnum
结果输出
简介
继之前 三个桶分八升水java版 后,《算法的乐趣》第六章-妖怪和和尚过河问题,和之前第五章的算法大同小异,巩固下对于树的深度遍历,以及在遍历的时候对于栈的使用,下面付上java版代码。代码
App.java
主类,包含了所有算法和流程package com.yixin.arithmetic.three; import com.yixin.arithmetic.three.enums.ActionEnum; import com.yixin.arithmetic.three.enums.BoatDirectionEnum; import com.yixin.arithmetic.three.model.ItemState; import java.util.Iterator; import java.util.Stack; /** * 有三个和尚和三个妖怪要利用一个小船过河 * 一个船同时最多只能做两个人,同时,无论在两岸还是再船上 * 当妖怪的数量大于和尚的数量时,和尚就会被吃掉 * 现在需要安排一种过河的方式,保证和尚和妖怪都能顺利过河,并且和尚不会被吃掉。 */ public class App { static int index = 0; private static Stack<ItemState> itemStateStack = new Stack<ItemState>(); public static void main( String[] args ) { ItemState itemState = new ItemState(); itemState.setLocalMonk(3); itemState.setLocalMonster(3); itemState.setBoatDirection(BoatDirectionEnum.LOCAL_2_REMOTE); itemStateStack.add(itemState); search(); } /** * 核心方法,查询,遍历树 */ public static void search(){ ItemState itemState = itemStateStack.peek(); ActionEnum[] actionEnumAry = ActionEnum.values(); logIfEnd(itemState); for(ActionEnum actionEnum : actionEnumAry){ if(!canAcross(itemState , actionEnum)){ continue; } ItemState nextItemState = across(itemState , actionEnum); if (isAlreadyProcess(nextItemState)) { continue; } //利用栈的数据结构,遍历树形结构 itemStateStack.add(nextItemState); search(); itemStateStack.pop(); } } /** * 查询当前状态是否可以过河 * @param itemState 当前状态 * @param actionEnum 当前尝试的动作 * @return 是否可以 */ private static boolean canAcross(ItemState itemState , ActionEnum actionEnum){ //移动后在local的和尚数量小于怪兽数量不行 //移动后在remote的和尚数量小于怪兽数量不行 //移动后local或remote的和尚和怪兽数量小于0不行 if(itemState.getBoatDirection() == actionEnum.nextBoatDirection){ return false; } if(itemState.getLocalMonk() + actionEnum.monkCount < 0 || itemState.getLocalMonster() + actionEnum.monsterCount < 0 || itemState.getRemoteMonk() - actionEnum.monkCount < 0 || itemState.getRemoteMonster() - actionEnum.monsterCount < 0){ return false; } if(itemState.getLocalMonk() + actionEnum.monkCount > 0 && itemState.getLocalMonk() + actionEnum.monkCount < itemState.getLocalMonster() + actionEnum.monsterCount){ return false; } if(itemState.getRemoteMonk() - actionEnum.monkCount >0 && itemState.getRemoteMonk() - actionEnum.monkCount < itemState.getRemoteMonster() - actionEnum.monsterCount){ return false; } return true; } /** * 真正过河的动作,会进行对象的复制和修改 * @param itemState 当前的状态 * @param actionEnum 当前变化的动作 * @return 复制后的对象,不会有引用地址相同的问题 */ private static ItemState across(ItemState itemState , ActionEnum actionEnum){ ItemState copyItemState = itemState.clone(); copyItemState.setLocalMonk(itemState.getLocalMonk() + actionEnum.monkCount); copyItemState.setLocalMonster(itemState.getLocalMonster() + actionEnum.monsterCount); copyItemState.setRemoteMonk(itemState.getRemoteMonk() - actionEnum.monkCount); copyItemState.setRemoteMonster(itemState.getRemoteMonster() - actionEnum.monsterCount); copyItemState.setBoatDirection(actionEnum.nextBoatDirection); copyItemState.setActionEnum(actionEnum); return copyItemState; } /** * 因为针对树形结构遍历,需要判断是否已经遍历过当前的节点,若遍历过,则结束 * @param itemState 当前的节点状态 * @return 是否被遍历过 */ private static boolean isAlreadyProcess(ItemState itemState){ Iterator<ItemState> itemStateIterator = itemStateStack.iterator(); while(itemStateIterator.hasNext()){ ItemState item = itemStateIterator.next(); if(item.equals(itemState)){ return true; } } return false; } /** * 如果结束打印日志 * 通过子节点,依次找到对应的父节点,打印出来 * @param itemState 结束的子节点 */ private static void logIfEnd(ItemState itemState){ if(itemState.getLocalMonk() == 0 && itemState.getLocalMonster() == 0){ index++; Iterator<ItemState> iterator = itemStateStack.iterator(); System.out.print(index+":"); while(iterator.hasNext()) { ItemState item = iterator.next(); System.out.print((item.getActionEnum() == null ? "" : item.getActionEnum().name()) + "[" + item.getLocalMonk() + "," + item.getLocalMonster() + "<->" + item.getRemoteMonk() + "," + item.getRemoteMonster() + "] ==> " ); } System.out.println(); } } }
ItemState.java
当前状态的实体类,保存了两岸的和尚和怪物的数量以及下次船的行走方向。此处不需要记录每一个和尚具体的状态,只需要确定他们的位置和数量即可,用于计算是否会被吃掉
package com.yixin.arithmetic.three.model; import com.yixin.arithmetic.three.enums.ActionEnum; import com.yixin.arithmetic.three.enums.BoatDirectionEnum; /** * Created by yixin on 16/12/12. */ public class ItemState implements Cloneable{ private int localMonster; private int remoteMonster; private int localMonk; private int remoteMonk; private BoatDirectionEnum boatDirection; private ActionEnum actionEnum; public int getLocalMonster() { return localMonster; } public void setLocalMonster(int localMonster) { this.localMonster = localMonster; } public int getRemoteMonster() { return remoteMonster; } public void setRemoteMonster(int remoteMonster) { this.remoteMonster = remoteMonster; } public int getLocalMonk() { return localMonk; } public void setLocalMonk(int localMonk) { this.localMonk = localMonk; } public int getRemoteMonk() { return remoteMonk; } public void setRemoteMonk(int remoteMonk) { this.remoteMonk = remoteMonk; } public BoatDirectionEnum getBoatDirection() { return boatDirection; } public void setBoatDirection(BoatDirectionEnum boatDirection) { this.boatDirection = boatDirection; } public ActionEnum getActionEnum() { return actionEnum; } public void setActionEnum(ActionEnum actionEnum) { this.actionEnum = actionEnum; } public ItemState clone(){ try { return (ItemState)super.clone(); } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ItemState itemState = (ItemState) o; if (localMonster != itemState.localMonster) return false; if (remoteMonster != itemState.remoteMonster) return false; if (localMonk != itemState.localMonk) return false; if (remoteMonk != itemState.remoteMonk) return false; return boatDirection == itemState.boatDirection; } @Override public int hashCode() { int result = localMonster; result = 31 * result + remoteMonster; result = 31 * result + localMonk; result = 31 * result + remoteMonk; result = 31 * result + (boatDirection != null ? boatDirection.hashCode() : 0); return result; } }
ActionEnum.java
枚举类,对于船的行动和常量的对应,主要为了减少主流程内的if else的代码。package com.yixin.arithmetic.three.enums; /** * Created by yixin on 16/12/12. */ public enum ActionEnum { TWO_MONSTER_GO(0 , -2 , BoatDirectionEnum.REMOTE_2_LOCAL), ONE_MONSTER_GO(0 , -1 , BoatDirectionEnum.REMOTE_2_LOCAL), ONE_MONK_GO(-1 , 0 , BoatDirectionEnum.REMOTE_2_LOCAL), TWO_MONK_GO(-2 , 0 , BoatDirectionEnum.REMOTE_2_LOCAL), ONE_MONSTER_ONE_MONK_GO(-1 , -1 , BoatDirectionEnum.REMOTE_2_LOCAL), TWO_MONSTER_BACK( 0 , 2 , BoatDirectionEnum.LOCAL_2_REMOTE), ONE_MONSTER_BACK(0 , 1 , BoatDirectionEnum.LOCAL_2_REMOTE), ONE_MONK_BACK(1 , 0 , BoatDirectionEnum.LOCAL_2_REMOTE), TWO_MONK_BACK(2 , 0 , BoatDirectionEnum.LOCAL_2_REMOTE), ONE_MONSTER_ONE_MONK_BACK( 1 , 1 , BoatDirectionEnum.LOCAL_2_REMOTE); public int monkCount; public int monsterCount; public BoatDirectionEnum nextBoatDirection; ActionEnum(int monkCount, int monsterCount, BoatDirectionEnum boatDirection) { this.monkCount = monkCount; this.monsterCount = monsterCount; this.nextBoatDirection = boatDirection; } }
BoatDirectionEnum
枚举类,定义船的方法。package com.yixin.arithmetic.three.enums; /** * Created by yixin on 16/12/12. */ public enum BoatDirectionEnum { LOCAL_2_REMOTE , REMOTE_2_LOCAL; }
结果输出
1:[3,3<->0,0] ==> TWO_MONSTER_GO[3,1<->0,2] ==> ONE_MONSTER_BACK[3,2<->0,1] ==> TWO_MONSTER_GO[3,0<->0,3] ==> ONE_MONSTER_BACK[3,1<->0,2] ==> TWO_MONK_GO[1,1<->2,2] ==> ONE_MONSTER_ONE_MONK_BACK[2,2<->1,1] ==> TWO_MONK_GO[0,2<->3,1] ==> ONE_MONSTER_BACK[0,3<->3,0] ==> TWO_MONSTER_GO[0,1<->3,2] ==> ONE_MONSTER_BACK[0,2<->3,1] ==> TWO_MONSTER_GO[0,0<->3,3] ==>2:[3,3<->0,0] ==> TWO_MONSTER_GO[3,1<->0,2] ==> ONE_MONSTER_BACK[3,2<->0,1] ==> TWO_MONSTER_GO[3,0<->0,3] ==> ONE_MONSTER_BACK[3,1<->0,2] ==> TWO_MONK_GO[1,1<->2,2] ==> ONE_MONSTER_ONE_MONK_BACK[2,2<->1,1] ==> TWO_MONK_GO[0,2<->3,1] ==> ONE_MONSTER_BACK[0,3<->3,0] ==> TWO_MONSTER_GO[0,1<->3,2] ==> ONE_MONK_BACK[1,1<->2,2] ==> ONE_MONSTER_ONE_MONK_GO[0,0<->3,3] ==>
3:[3,3<->0,0] ==> ONE_MONSTER_ONE_MONK_GO[2,2<->1,1] ==> ONE_MONK_BACK[3,2<->0,1] ==> TWO_MONSTER_GO[3,0<->0,3] ==> ONE_MONSTER_BACK[3,1<->0,2] ==> TWO_MONK_GO[1,1<->2,2] ==> ONE_MONSTER_ONE_MONK_BACK[2,2<->1,1] ==> TWO_MONK_GO[0,2<->3,1] ==> ONE_MONSTER_BACK[0,3<->3,0] ==> TWO_MONSTER_GO[0,1<->3,2] ==> ONE_MONSTER_BACK[0,2<->3,1] ==> TWO_MONSTER_GO[0,0<->3,3] ==>
4:[3,3<->0,0] ==> ONE_MONSTER_ONE_MONK_GO[2,2<->1,1] ==> ONE_MONK_BACK[3,2<->0,1] ==> TWO_MONSTER_GO[3,0<->0,3] ==> ONE_MONSTER_BACK[3,1<->0,2] ==> TWO_MONK_GO[1,1<->2,2] ==> ONE_MONSTER_ONE_MONK_BACK[2,2<->1,1] ==> TWO_MONK_GO[0,2<->3,1] ==> ONE_MONSTER_BACK[0,3<->3,0] ==> TWO_MONSTER_GO[0,1<->3,2] ==> ONE_MONK_BACK[1,1<->2,2] ==> ONE_MONSTER_ONE_MONK_GO[0,0<->3,3] ==>
相关文章推荐
- 妖怪与和尚过河问题(java语言)
- 学java i/o库要掌握的三个关键知识点
- 提高Java代码可重用性的三个措施
- 提高Java代码可重用性的三个措施
- JAVA直连SQL SERVER 2000的三个驱动包
- 三个和尚没水喝
- 三个和尚的故事与项目机构管理
- 轻松有效检查Java代码的三个工具
- 从三个和尚到中国的企业管理
- java面向对象浅析系列1——三个基本特征
- 学习java i/o库要掌握的三个关键知识点
- 轻松有效检查Java代码的三个工具
- 管理笑话-三个和尚没水喝
- JAVA进阶:提高代码可重用性的三个措施
- 三个和尚
- 提高Java代码可重用性的三个措施
- 【转】提高Java代码可重用性的三个措施
- 三个利用Java实现zip压缩/解压缩方法
- JAVA中常用需要设置的三个环境变量(JAVA_HOME、CLASSPATH、PATH)
- java.io.File 中 getPath(), getAbsolutePath() 和 getCanonicalPath() 三个方法的区别