当前位置 博文首页 > lenkee的博客:算法小程序:倒水问题

    lenkee的博客:算法小程序:倒水问题

    作者:[db:作者] 时间:2021-08-31 19:18

    问题描述

    有三个容积分别为3,5,8升的水桶,其中容积为8升的水桶中装了水,容积为3,5的水桶为空。水桶没有刻度尺,现在需要将水桶中的8升水等分成2分,每份都是4升水,该怎么分。总共有多少种分方法

    思路

    水桶分别为3L,5L,8L,而且没有刻度尺衡量倒多少水,所有倒水要么被装的水桶倒满,要么倒水的桶倒完。
    我们可以给每个桶标记一种状态,初始状态就是8L水桶满,其余两个水桶为空,每倒一次,两个桶的状态会改变,动态递归算法,把每一种水桶可以倒的情况都尝试一遍,直到满足两个4L水为止。但是,这样有可能会出现重复的情况,比如8L水桶倒向3L水桶,3L水桶又倒回8L水桶,这样状态就重复了,永远都倒不完,所有,我们把每步走的状态都放到栈中,如果出现重复状态,立即结束当前倒水

    代码实例

    下面使用java实现的

    import java.util.ArrayList;
    import java.util.List;
    
    public class 倒水问题 {
    
    	/*
    	 * 有三个容积分别为3,5,8升的水桶,其中容积为8升的水桶中装了水,容积为3,5的水桶为空。
    	 * 水桶没有刻度尺,现在需要将水桶中的8升水等分成2分,每份都是4升水,该怎么分。
    	 * 总共有多少种分方法
    	 */
    	
    	public static void main(String[] args) {
    		Action a = new Action();
    		a.bucket[0]=8;
    		a.bucket[1]=0;
    		a.bucket[2]=0;
    		fun(a);
    		System.out.println("共有:"+num+"种");
    
    	}
    	//水桶规则
    	public static final int[]rule = {8,5,3};
    	//记录有多少种分法
    	public static int num=0;
    	//分水执行的动作,包括水桶状态,分水的情况
    	//----------------------------------------------------------------
    	//倒水情况
    	public static void fun(Action action){
    		//出口,当平分,或者回路时退出
    		for (int[] r : action.rout) {
    			if(isequal(r, action.bucket))	//如果两个水桶水相同,即走到了回路,停止
    					return;
    		}
    		//添加新路径
    		{
    			int []t = new int[3];
    			for (int i = 0; i < action.bucket.length; i++) {
    				t[i]=action.bucket[i];
    			}
    			action.rout.add(t);
    		}
    		//判断平分
    		if(action.bucket[0]==4 && action.bucket[1]==4){
    			for (int[] r : action.rout) {
    				System.out.print(r[0]+":"+r[1]+":"+r[2]+":"+"--->");
    			}
    			System.out.println();
    			num++;
    			return;
    		}
    		//---------
    		//6种倒法
    		if(canPour(0, 1, action))	//1倒2
    		{
    			Action tem = new Action();	//临时存储,一会儿还要变回去
    			copy(tem,action);
    			//倒水
    			pour(0, 1, action);	
    			fun(action);
    			action=tem;
    		}
    		if(canPour(0, 2, action))	//1倒3
    		{
    			Action tem = new Action();	//临时存储,一会儿还要变回去
    			copy(tem,action);
    			//倒水
    			pour(0, 2, action);
    			fun(action);
    			action=tem;
    		}
    		if(canPour(1, 0, action))	//2倒1
    		{
    			Action tem = new Action();	//临时存储,一会儿还要变回去
    			copy(tem,action);
    			//倒水
    			pour(1, 0, action);
    			fun(action);
    			action=tem;
    		}
    		if(canPour(1, 2, action))	//2倒3
    		{
    			Action tem = new Action();	//临时存储,一会儿还要变回去
    			copy(tem,action);
    			//倒水
    			pour(1, 2, action);
    			fun(action);
    			action=tem;
    		}
    		if(canPour(2, 0, action))	//3倒1
    		{
    			Action tem = new Action();	//临时存储,一会儿还要变回去
    			copy(tem,action);
    			//倒水
    			pour(2, 0, action);
    			fun(action);
    			action=tem;
    		}
    		if(canPour(2, 1, action))	//3倒2
    		{
    			Action tem = new Action();	//临时存储,一会儿还要变回去
    			copy(tem,action);
    			//倒水
    			pour(2, 1, action);
    			fun(action);
    			action=tem;
    		}
    		
    		
    	}
    	//----------------------------------------------------------------
    	
    	//判断两数组值是否相等
    	public static boolean isequal(int[] a1 ,int[] a2){
    		if(a1.length!=a2.length)
    			return false;
    		for (int i = 0; i < a2.length; i++) {
    			if(a1[i]!=a2[i])
    				return false;
    		}
    		return true;
    	}
    	
    	//判断是否能倒水,不考虑是否存在以前倒过的情况
    	public static boolean canPour(int from, int to,Action action){
    		/*
    		 * to水桶满:false
    		 * from水桶空:false
    		 * from水桶水+to水桶水>to水桶量:false
    		 * from=to不能倒
    		 */
    		if(from==to)
    			return false;
    		if(action.bucket[from]==0)
    			return false;
    		if(action.bucket[to]==rule[to])
    			return false;
    //		if(action.bucket[from]+action.bucket[to]>rule[to])
    //			return false;
    		return true;
    	}
    	
    	//倒水
    	public static void pour(int from,int to,Action action){
    		//分两种,多倒少,少倒多
    		int remain = rule[to]-action.bucket[to];
    		if(action.bucket[from]>=remain){		//是否多倒少
    			action.bucket[from]-=remain;
    			action.bucket[to]=rule[to];
    		}else{	//少倒多情况
    			action.bucket[to]+=action.bucket[from];
    			action.bucket[from]=0;
    		}
    	}
    	//把action给tem
    	public static void copy(Action tem,Action action){
    		for (int i = 0; i < action.bucket.length; i++) {
    			tem.bucket[i]=action.bucket[i];
    		}
    		for (int[] r : action.rout) {
    			int[] t = new int[3];
    			for
    
    下一篇:没有了