题目---倒油问题

共有三个瓶子,容量分别为12,8,5 
现有油12斤放在容量为12斤的瓶子中,问怎么样能倒出6斤油?

/*
思路:因为不知道怎么倒油,所以只能乱碰,也就是穷举法,把所有倒油的步骤都搞出来,然后判断是否倒出想要的结果,如果得到了想要的结果,那么就不倒了,对于每一种到完后的状态,如果不符合要求,那么每一个桶又都可以是src和target

与字母全排列最大的不同是,字母全排列中因为每个下一步都需要成为一个结果,那么就把每个下一步放入递归函数,而倒油问题是下一步可能的集合中只有一个符合结果,或者不符合结果,如果符合结果则打印,不符合结果则递归
*/

/*如何实现穷举是关键,穷举什么:在每一次倒油的选择中出油桶应该试着倒到每一个目标桶中,也就是第一个桶需要试着倒到第二个桶,第三个桶。。。中
那么如何确定出油桶呢。。?
当然每个桶都有权利做出油桶

*/
class Barrel {
		int maxCapac; // 最大容量,不要设emptyCapac,如果设置两个变化的东西,程序会很难写,所以把emptyCapac变成一个方法
		int curCapac;// 当前拥有的容量

		public void pop(int num) { // 作为出油桶,倒出油
			// 如果目标桶没容量或者出油桶没油,都不能倒
			curCapac -= num;
		}

		public void push(int num) { // 作为目标桶,倒入油
			curCapac += num;
		}

		public int getEmptyCapacity() {
			return maxCapac - curCapac;
		}
	}

	class BarrelManager {
		
		private List<String> steps = new ArrayList<String>();
		
		private void go(List<Barrel[]> nextBarStatuses){
			for(Barrel[] b : nextBarStatuses){
				if(b[0].curCapac == 6 || b[1].curCapac==6 || b[2].curCapac == 6){//下面的走法中只有一种走法可能可行
					System.out.println("倒油完成 A="+b[0].curCapac+" B="+b[1].curCapac+" C="+b[2].curCapac);
				    break;
				}else{
System.out.println("倒油未完成 A="+b[0].curCapac+" B="+b[1].curCapac+" C="+b[2].curCapac);

				go(getNextSteps(b));
                                     }
			}
			
		}
		
		
		/**
		 * 得到所有下一步的正确的桶的状态,这个方法得到的是前一种状态下面的每一种倒油状态所导致的下一种走法
		 */
		public List getNextSteps(Barrel[] barrels) {
			List<Barrel[]> nextBarStatuses= new ArrayList<Barrel[]>();
			for (int sourcei = 0; sourcei < barrels.length; sourcei++) {// 每一个桶都有机会做出油桶
				for (int targeti = 0; targeti < barrels.length; targeti++) { // 每个桶有有机会做目标桶
					if (sourcei == targeti)
						continue; // 如果出油桶==目标桶,不给自己倒

					int minNum = Math.min(barrels[sourcei].curCapac,
							barrels[targeti].getEmptyCapacity());
					barrels[sourcei].pop(minNum);
					barrels[targeti].push(minNum);
					
					//判断是否倒油步骤出现过,这里用字符串,是技巧哈
					String step = "A="+barrels[0].curCapac+",B="+barrels[1].curCapac+",C="+barrels[2].curCapac;
					if(steps.contains(step)){ //如果倒油步骤出现过,避免死循环,就不进行下面的了
						rollback(barrels, sourcei, targeti, minNum);
						continue;
					}
				    steps.add(step); //记录这时的状态
					
				    Barrel[] bs = cloneBarrel(barrels);
					list.add(bs);
					
					rollback(barrels, sourcei, targeti, minNum);
				}
			}
			 return nextBarStatuses;
		}

		private void rollback(Barrel[] barrels, int sourcei, int targeti,
				int minNum) {
			barrels[sourcei].push(minNum);  //还原状态
			barrels[targeti].pop(minNum);
		}
		
		private Barrel[] cloneBarrel(Barrel[] barrels){
			Barrel b1 = new Barrel();
			b1.maxCapac =barrels[0].maxCapac;
			b1.curCapac = barrels[0].curCapac;
			
			Barrel b2 = new Barrel();
			b2.maxCapac =barrels[1].maxCapac;
			b2.curCapac = barrels[1].curCapac;
			
			Barrel b3 = new Barrel();
			b3.maxCapac =barrels[2].maxCapac;
			b3.curCapac = barrels[2].curCapac;
			return new Barrel[]{b1,b2,b3};
		}
	}

你可能感兴趣的:(C++,c,C#,Go)