(dfs)韩信走马分酒问题

 泊松是法国数学家、物理学家和力学家。他一生致力科学事业,成果颇多。有许多著名的公式定理以他的名字命名,比如概率论中著名的泊松分布。
 有一次闲暇时,他提出过一个有趣的问题,后称为:“泊松分酒”。在我国古代也提出过类似问题,遗憾的是没有进行彻底探索,其中流传较多是:“韩信走马分油”问题。

 有3个容器,容量分别为12升,8升,5升。其中12升中装满油,另外两个空着。要求你只用3个容器操作,最后使得某个容器中正好有6升油。

 下面的列表是可能的操作状态记录:
 12,0,0
 4,8,0
 4,3,5
 9,3,0
 9,0,3
 1,8,3
 1,6,5

 每行3个数据,分别表示12,8,6升容器中的油量

 第一行表示初始状态,第二行表示把12升倒入8升容器后的状态,第三行是8升倒入5升,...

 当然,同一个题目可能有多种不同的正确操作步骤。

   本题目的要求是,请你编写程序,由用户输入:各个容器的容量,开始的状态,和要求的目标油量,程序则通过计算输出一种实现的步骤(不需要找到所有可能的方法)。     如 果没有可能实现,则输出:“不可能”。

    例如,用户输入:
   12,8,5,12,0,0,6

   用户输入的前三个数是容器容量(由大到小),接下来三个数是三个容器开始时的油量配置,最后一个数是要求得到的油量(放在哪个容器里得到都可以)

    则程序可以输出(答案不唯一,只验证操作可行性):
  12,0,0
  4,8,0
  4,3,5
  9,3,0
  9,0,3
  1,8,3
  1,6,5

   每一行表示一个操作过程中的油量状态。

  注意:

   请仔细调试!您的程序只有能运行出正确结果的时候才有机会得分!

package JiaNan;
import java.util.Scanner;  
import java.util.Stack;  
public class WaterPouring2012_10 
{  
	public static int A,B,C;   //三个杯子的容量  
	public static Stack<Integer[]> road=new Stack<Integer[]>();   //记录倒水步骤  
	public static boolean[][][] vis;   //这个数组不错,记录空间树节点是否被访问
    public static int num=0;    //记录解的数量  
	public static int aim;      //目标水量  
	public static void main(String[] args) 
	{  
		// TODO Auto-generated method stub  
        Scanner sc=new Scanner(System.in);  
		A=sc.nextInt();  
		B=sc.nextInt();  
		C=sc.nextInt();  
		
		vis=new boolean[2*A][2*A][2*A];  //注意这里全部是A,因此注意杯子大小,提前输入数据时就排好序
        for(int i=0;i<A*2;i++)  
            for(int j=0;j<A*2;j++)  
                for(int k=0;k<A*2;k++)  
                    vis[i][j][k]=false;  
				
				int Astart=sc.nextInt();  
				int Bstart=sc.nextInt();  
				int Cstart=sc.nextInt();  
				
				aim=sc.nextInt();   
				road.push(new Integer[]{Astart,Bstart,Cstart});  
				Pouring(Astart,Bstart,Cstart);  
				if(num==0)  
				{  
					System.out.println("不可能");  
				}  
    }  
	
	public static void Pouring(int x,int y,int z)  
    {  
        if(x==aim||y==aim||z==aim)  //如果得到了目标解,就将计数器加1,打印出倒水过程
        {  
			num++;  
			System.out.println("方案"+num+":");  
			PrintRoad(); 
			System.out.println();
			return;
        }  
		else if(x<=A&&y<=B&&z<=C&&!vis[x][y][z])   //如果空间树节点没被访问过  
        {  
			vis[x][y][z]=true;     //该节点的所有子结点全部被访问  
			//A->B A倒空  
			if(x+y<B && x>0)  
			{  
				//System.out.print("A->B A倒空");  
				road.push(new Integer[]{0, x+y, z});  
                Pouring(0, x+y, z);  
                road.pop();                            //这里巧妙运用堆栈,用push代表执行某过程,下面的pop代表恢复
            }  
			//A->B B倒满  
			if(y<B && x>0 && (x+y)>=B)  
            {  
				//System.out.print("A->B B倒满");  
				road.push(new Integer[]{x+y-B, B, z});  
				Pouring(x+y-B, B, z);  
                road.pop();  
			}  
            //A->C A倒空  
            if(x+z<C && x>0)  
			{  
				//System.out.print("A->C A倒空");  
				road.push(new Integer[]{0,y,x+z});  
				Pouring(0,y,x+z);  
				road.pop();  
			}  
            //A->C C倒满  
			if(z<C && x>0 && x+z>=C)  
			{  
				//System.out.print("A->C C倒满");  
                road.push(new Integer[]{x+z-C,y,C});  
				Pouring(x+z-C,y,C);  
                road.pop();  
            }  
			
			//B->A B倒空  
			if(x+y<=A && y>0)  
			{  
				//System.out.print("B->A B倒空");  
                road.push(new Integer[]{x+y,0,z});  
				Pouring(x+y,0,z);  
                road.pop();  
			}  
            //B->A A倒满  
            if(x<A && y>0 && y+x>=A)  
            {  
				//System.out.print("B->A A倒满");  
				road.push(new Integer[]{A,x+y-A,z});  
                Pouring(A,x+y-A,z);  
				road.pop();  
			}  
			//B->C B倒空  
			if(y+z<C && y>0)  
            {  
				//System.out.print("B->C B倒空");  
				road.push(new Integer[]{x,0,y+z});  
                Pouring(x,0,y+z);  
				road.pop();  
			}  
            //B->C C倒满  
            if(z<C && y>0 && y+z>=C)  
			{  
                //System.out.print("B->C C倒满");  
				road.push(new Integer[]{x,y+z-C,C});  
                Pouring(x,y+z-C,C);  
                road.pop();  
			}  
			
            //C->A C倒空  
            if(x+z<=A && z>0)  
			{  
				//System.out.print("C->A C倒空");  
				road.push(new Integer[]{x+z,y,0});  
				Pouring(x+z,y,0);  
				road.pop();  
			}
			//C->A A倒满  
			if(x<A && z>0 && x+z>=A)  
			{  
				//System.out.print("C->A A倒满");  
				road.push(new Integer[]{A,y,x+z-A});  
				Pouring(A,y,x+z-A);  
				road.pop();  
			}  
			//C->B C倒空  
			if((B-y)>z&&z>0)  
			{  
				//System.out.print("C->B C倒空");  
				road.push(new Integer[]{x,y+z,0});  
				Pouring(x,y+z,0);  
				road.pop();  
			}  
			//C->B B倒满  
			if(y<B && z>0 && y+z>=B)  
			{  
				//System.out.print("C->B B倒满");  
				road.push(new Integer[]{x,B,y+z-B});  
				Pouring(x,B,y+z-B);  
				road.pop();  
			}    
        }    
    }  
	
	public static void PrintRoad()  
    {  
		for(int i=0;i<road.size();i++)  
		{  
            Integer[] tmp=road.get(i);  
            System.out.println("("+tmp[0]+","+tmp[1]+","+tmp[2]+")");  
		}  
        //road.push(new Integer[]{A,0,0});  
	}  
	
}  
/*
12 8 5 12 0 0 6
方案1:
(12,0,0)
(4,8,0)
(0,8,4)
(8,0,4)
(8,4,0)
(3,4,5)
(3,8,1)
(11,0,1)
(11,1,0)
(6,1,5)

方案2:
(12,0,0)
(4,8,0)
(4,3,5)
(9,3,0)
(9,0,3)
(1,8,3)
(1,6,5)

*/


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值