三个桶分八升水java版
简介
最近在看《算法的乐趣》文中讲到经典算法三个桶分八升水的算法是用c++写的,自己就动手把他换成了java版。以下是代码,有不足的请各位大牛指出,谢谢!
代码
App.java
主类,包含了所有算法和流程
package com.yixin.three;
import com.yixin.three.model.BucketStatus;
import com.yixin.three.model.BucketWater;
import java.util.*;
/**
* xinwei.cheng
* 三个桶分八升水的代码
* 深度优先搜索算法 利用stack栈会减少很多代码量
*/
public class App {
private static int index = 0;
private static Stack<BucketStatus> bucketStatusQueue = new Stack<>();
public static void main( String[] args ) throws CloneNotSupportedException {
BucketWater bucketWater1 = new BucketWater(1, 8 , 8);
BucketWater bucketWater2 = new BucketWater(2, 0 , 5);
BucketWater bucketWater3 = new BucketWater(3, 0 , 3);
BucketStatus bucketStatus = new BucketStatus();
bucketStatus.getBucketWaterAry()[0] = bucketWater1;
bucketStatus.getBucketWaterAry()[1] = bucketWater2;
bucketStatus.getBucketWaterAry()[2] = bucketWater3;
bucketStatusQueue.add(bucketStatus);
search();
}
/**
* 核心查找方法
* @throws CloneNotSupportedException
*/
public static void search() throws CloneNotSupportedException {
//从栈中获取顶端的元素
BucketStatus bucketStatus = bucketStatusQueue.peek();
//判断是否结束,若结束了打印日志
//放在上面判断因为递归必须需要进入此方法,方法退出后才会pop,在这里打印可以获取所有路径
if(isEnd(bucketStatus)){
logProcess();
}
BucketWater[] bucketWaterAry = bucketStatus.getBucketWaterAry();
for(int i = 0 ; i < bucketWaterAry.length ; i ++){
for(int j = 0 ; j < bucketWaterAry.length ; j ++){
//判断是否可以倒水 并获取可以倒水的量
int pushWater = canPush(bucketWaterAry[i] , bucketWaterAry[j]);
if(pushWater == 0 ) {
continue;
}
//这里返回的对象已经被clone了,没有指针引用的问题
//在后期处理直接压入栈
BucketStatus nextBucketStatus = push(bucketStatus , i , j , pushWater);
//判断当前的状态是否已经处理过 循环栈即可获得
//在这里不需要添加到的水量,可以想象为一个树型结构,即该节点是否处理过,以节点为一个维度
if(isAlreadyProcess(nextBucketStatus)){
continue;
}
bucketStatusQueue.add(nextBucketStatus);
search();
//pop只会pop扫描到的子节点
bucketStatusQueue.pop();
}
}
}
/**
* 倒水
*/
public static BucketStatus push(BucketStatus bucketStatus , Integer fromIndex, Integer toIndex , int pushWater) throws CloneNotSupportedException {
BucketStatus copyBucketStatus = bucketStatus.clone();
BucketWater bucketWaterFrom = copyBucketStatus.getBucketWaterAry()[fromIndex];
BucketWater bucketWaterTo = copyBucketStatus.getBucketWaterAry()[toIndex];
bucketWaterFrom.setRemainWater(bucketWaterFrom.getRemainWater() - pushWater);
bucketWaterTo.setRemainWater(bucketWaterTo.getRemainWater() + pushWater);
return copyBucketStatus;
}
/**
* 判断是否可以倒入水
* @param bucketWaterFrom
* @param bucketWaterTo
* @return
*/
public static int canPush(BucketWater bucketWaterFrom , BucketWater bucketWaterTo){
//相同的水桶号 不能倒入水
if(bucketWaterFrom.getIndex() == bucketWaterTo.getIndex()){
return 0;
}
//满的桶 不能导入水
if(bucketWaterTo.getRemainWater() == bucketWaterTo.getCapacity()){
return 0;
}
//没有水 不能倒
if(bucketWaterFrom.getRemainWater() == 0){
return 0;
}
//可以倒入的水
int canPushWater = bucketWaterTo.getCapacity() - bucketWaterTo.getRemainWater();
return bucketWaterFrom.getRemainWater() <= canPushWater ? bucketWaterFrom.getRemainWater() : canPushWater;
}
/**
* 判断当前这个流程是否之前处理过
* @return
*/
public static boolean isAlreadyProcess(BucketStatus bucketStatus){
Iterator<BucketStatus> iterator = bucketStatusQueue.iterator();
while(iterator.hasNext()){
BucketStatus bucket = iterator.next();
if(bucket.getBucketWaterAry()[0].getRemainWater() == bucketStatus.getBucketWaterAry()[0].getRemainWater() &&
bucket.getBucketWaterAry()[1].getRemainWater() == bucketStatus.getBucketWaterAry()[1].getRemainWater() &&
bucket.getBucketWaterAry()[2].getRemainWater() == bucketStatus.getBucketWaterAry()[2].getRemainWater()){
return true;
}
}
return false;
}
/**
* 判断是否查找到了解决路径
* @param bucketStatus
* @return
*/
public static boolean isEnd(BucketStatus bucketStatus){
int index = 2;
for(BucketWater bucketWater : bucketStatus.getBucketWaterAry()){
if(bucketWater.getRemainWater() == 4){
index--;
}
}
return index == 0;
}
/**
* 成功时输出
*/
public static void logProcess(){
index++;
Iterator<BucketStatus> iterator = bucketStatusQueue.iterator();
System.out.print(index + ":");
while(iterator.hasNext()) {
BucketStatus bucket = iterator.next();
System.out.print("[" + bucket.getBucketWaterAry()[0].getRemainWater() + "," + bucket.getBucketWaterAry()[1].getRemainWater() + "," + bucket.getBucketWaterAry()[2].getRemainWater() + "] ==>");
}
System.out.println();
}
}
BucketStatus.java
桶状态的实体类,主要为了保存3个桶创建的对象
package com.yixin.three.model;
/**
* @author xinwei.cheng
*/
public class BucketStatus implements Cloneable {
private BucketWater[] bucketWaterAry = new BucketWater[3];
public BucketStatus() {
}
public BucketWater[] getBucketWaterAry() {
return bucketWaterAry;
}
public void setBucketWaterAry(BucketWater[] bucketWaterAry) {
this.bucketWaterAry = bucketWaterAry;
}
@Override
public BucketStatus clone() throws CloneNotSupportedException {
BucketStatus bucketStatus = (BucketStatus)super.clone();
BucketWater[] bucketWaterAry = new BucketWater[3];
for(int i = 0; i < this.bucketWaterAry.length ; i ++){
bucketWaterAry[i] = this.bucketWaterAry[i].clone();
}
bucketStatus.bucketWaterAry = bucketWaterAry;
return bucketStatus;
}
}
BucketWater.java
桶的实体类,用于包装容量和剩余的水
package com.yixin.three.model;
/**
* @author xinwei.cheng
*/
public class BucketWater implements Cloneable {
private int index;
private int capacity;
private int remainWater;
public BucketWater() {
}
public BucketWater(int index, int remainWater , int capacity) {
this.index = index;
this.remainWater = remainWater;
this.capacity = capacity;
}
public int getRemainWater() {
return remainWater;
}
public void setRemainWater(int remainWater) {
this.remainWater = remainWater;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public int getCapacity() {
return capacity;
}
public void setCapacity(int capacity) {
this.capacity = capacity;
}
@Override
public BucketWater clone() throws CloneNotSupportedException {
return (BucketWater)super.clone();
}
}
结果
1:[8,0,0] ==>[3,5,0] ==>[0,5,3] ==>[5,0,3] ==>[5,3,0] ==>[2,3,3] ==>[2,5,1] ==>[7,0,1] ==>[7,1,0] ==>[4,1,3] ==>[4,4,0] ==>
2:[8,0,0] ==>[3,5,0] ==>[3,2,3] ==>[0,5,3] ==>[5,0,3] ==>[5,3,0] ==>[2,3,3] ==>[2,5,1] ==>[7,0,1] ==>[7,1,0] ==>[4,1,3] ==>[4,4,0] ==>
3:[8,0,0] ==>[3,5,0] ==>[3,2,3] ==>[5,0,3] ==>[5,3,0] ==>[2,3,3] ==>[2,5,1] ==>[7,0,1] ==>[7,1,0] ==>[4,1,3] ==>[4,4,0] ==>
4:[8,0,0] ==>[3,5,0] ==>[3,2,3] ==>[6,2,0] ==>[6,0,2] ==>[1,5,2] ==>[0,5,3] ==>[5,0,3] ==>[5,3,0] ==>[2,3,3] ==>[2,5,1] ==>[7,0,1] ==>[7,1,0] ==>[4,1,3] ==>[4,4,0] ==>
5:[8,0,0] ==>[3,5,0] ==>[3,2,3] ==>[6,2,0] ==>[6,0,2] ==>[1,5,2] ==>[1,4,3] ==>[0,5,3] ==>[5,0,3] ==>[5,3,0] ==>[2,3,3] ==>[2,5,1] ==>[7,0,1] ==>[7,1,0] ==>[4,1,3] ==>[4,4,0] ==>
6:[8,0,0] ==>[3,5,0] ==>[3,2,3] ==>[6,2,0] ==>[6,0,2] ==>[1,5,2] ==>[1,4,3] ==>[5,0,3] ==>[5,3,0] ==>[2,3,3] ==>[2,5,1] ==>[7,0,1] ==>[7,1,0] ==>[4,1,3] ==>[4,4,0] ==>
7:[8,0,0] ==>[3,5,0] ==>[3,2,3] ==>[6,2,0] ==>[6,0,2] ==>[1,5,2] ==>[1,4,3] ==>[4,4,0] ==>
8:[8,0,0] ==>[3,5,0] ==>[3,2,3] ==>[6,2,0] ==>[6,0,2] ==>[5,0,3] ==>[5,3,0] ==>[2,3,3] ==>[2,5,1] ==>[7,0,1] ==>[7,1,0] ==>[4,1,3] ==>[4,4,0] ==>
9:[8,0,0] ==>[5,0,3] ==>[0,5,3] ==>[3,5,0] ==>[3,2,3] ==>[6,2,0] ==>[6,0,2] ==>[1,5,2] ==>[1,4,3] ==>[4,4,0] ==>
10:[8,0,0] ==>[5,0,3] ==>[5,3,0] ==>[3,5,0] ==>[3,2,3] ==>[6,2,0] ==>[6,0,2] ==>[1,5,2] ==>[1,4,3] ==>[4,4,0] ==>
11:[8,0,0] ==>[5,0,3] ==>[5,3,0] ==>[2,3,3] ==>[0,5,3] ==>[3,5,0] ==>[3,2,3] ==>[6,2,0] ==>[6,0,2] ==>[1,5,2] ==>[1,4,3] ==>[4,4,0] ==>
12:[8,0,0] ==>[5,0,3] ==>[5,3,0] ==>[2,3,3] ==>[2,5,1] ==>[0,5,3] ==>[3,5,0] ==>[3,2,3] ==>[6,2,0] ==>[6,0,2] ==>[1,5,2] ==>[1,4,3] ==>[4,4,0] ==>
13:[8,0,0] ==>[5,0,3] ==>[5,3,0] ==>[2,3,3] ==>[2,5,1] ==>[7,0,1] ==>[7,1,0] ==>[3,5,0] ==>[3,2,3] ==>[6,2,0] ==>[6,0,2] ==>[1,5,2] ==>[1,4,3] ==>[4,4,0] ==>
14:[8,0,0] ==>[5,0,3] ==>[5,3,0] ==>[2,3,3] ==>[2,5,1] ==>[7,0,1] ==>[7,1,0] ==>[4,1,3] ==>[0,5,3] ==>[3,5,0] ==>[3,2,3] ==>[6,2,0] ==>[6,0,2] ==>[1,5,2] ==>[1,4,3] ==>[4,4,0] ==>
15:[8,0,0] ==>[5,0,3] ==>[5,3,0] ==>[2,3,3] ==>[2,5,1] ==>[7,0,1] ==>[7,1,0] ==>[4,1,3] ==>[4,4,0] ==>
16:[8,0,0] ==>[5,0,3] ==>[5,3,0] ==>[2,3,3] ==>[2,5,1] ==>[3,5,0] ==>[3,2,3] ==>[6,2,0] ==>[6,0,2] ==>[1,5,2] ==>[1,4,3] ==>[4,4,0] ==>
Process finished with exit code 0