三个桶分八升水java版

三个桶分八升水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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值