您的位置:首页 > 编程语言 > Java开发

三个怪兽和三个和尚过河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 算法