题目:有一位厨师要从盛12斤油(a桶)的桶中倒出6斤油来,可是手边只有盛8斤油(b桶)和盛5斤油(c桶)的两个桶,问如何操作才能将6斤取出来呢?
注意:这道题不能把放入集合的元素弹出,不然会陷入死循环。
----1)栈,其实只要用集合就可以了
package cn.hncu.search.oil.common;
/*
* MyStack-我的栈
* 这个类是用来保存倒油路径的,
* 通过子节点,可以找到父节点。
* 用递归实现。
* 因为不知道倒油的个数所以需要一个集合,
* 来保存数据,且每一个数据必须是new出来的,
* 不然会捆绑的。
* 测试内容:
* 1)栈满
* 2)栈空
* 集合测试签名:lq
*/
public class MyStack {
/*
* objs对象数组,可以装下所有的数据,
* Object是所有类的父类。
* end尾指针
* 这个做成循环队列
*/
Object[] objs = new Object[0];
int end;
/*
* 这里直接把集合的大小定死,
* 就是为了方便写题。
*/
public MyStack() {
objs = new Object[100];
}
/*
* 获得所有元素,
*/
public Object[] getAll() {
Object[] objTemps = new Object[end];
for (int i = 0; i < objTemps.length; i++) {
objTemps[i] = objs[i];
}
return objTemps;
}
/*
* push-压入
* 将元素压入集合
*/
public void push(Object obj) {
if (isFull()) {
return;
}
if (contain(obj)) {
return;
}
objs[end] = obj;
end++;
}
/*
* 是否包含
*/
public boolean contain(Object obj) {
for (int i = 0; i < objs.length; i++) {
if (obj.equals(objs[i])) {
return true;
}
}
return false;
}
/*
* pop-弹出
* 将队首元素弹出
*/
public Object pop() {
if (isEmpty()) {
return null;
}
Object obj = objs[end - 1];
objs[end - 1] = null;
end--;
return obj;
}
/*
* isEmpty-是否为空
* 这个函数是为了判断集合是否为空。
*/
public boolean isEmpty() {
if (0 == end) {
return true;
}
return false;
}
/*
* isFull-是否为满
* 判断集合是否为满
*/
public boolean isFull() {
if (end + 1 >= objs.length) {
System.out.println("栈满。。。");
return true;
}
return false;
}
}
-----2)桶类
package cn.hncu.search.oil.common;
/*
* Bucket-桶
*/
public class Bucket {
int capacity;
public int now;
public Bucket(int capacity, int now) {
this.capacity = capacity;
this.now = now;
}
public Bucket(Bucket b) {
this.capacity = b.capacity;
this.now = b.now;
}
/*
* canIn-能够倒入多少油
*/
public int canIn() {
return capacity - now;
}
/*
* canOut-能够倒出多少油
*/
public int canOut() {
return now;
}
/*
* bulk-体积
* in表示能够倒入的油量
*/
public void in(int bulk) {
if (bulk > canIn()) {
now += canIn();
} else {
now += bulk;
}
}
/*
* volume-体积
* out表示倒出多少油
*/
public void out(int volume) {
if (volume > canOut()) {
now = 0;
} else {
now -= volume;
}
}
/*
* 方便测试数据,
* 这里我将这个方法用来测试集合空与满。
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "[capacity=" + capacity + ", now=" + now + "]";
}
}
-----3)桶结点类
package cn.hncu.search.oil.common;
import java.util.Arrays;
/*
* NodeOfBucket-桶的结点
*/
public class NodeOfBucket {
/*
* bts-buckets的缩写
*/
public Bucket[] bts = new Bucket[0];
public NodeOfBucket parent = null;
public NodeOfBucket(Bucket[] bts) {
this.bts = bts;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(bts);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
NodeOfBucket other = (NodeOfBucket) obj;
for (int i = 0; i < bts.length; i++) {
if (other.bts[i].now != this.bts[i].now) {
return false;
}
}
return true;
}
@Override
public String toString() {
return "A:" + bts[0].now + " B:" + bts[1].now + " C:" + bts[2].now;
}
/*
* 实现深拷贝
*/
public NodeOfBucket(NodeOfBucket nb) {
bts = new Bucket[nb.bts.length];
for (int i = 0; i < bts.length; i++) {
bts[i] = new Bucket(nb.bts[i]);
}
}
}
----4)Main函数
package cn.hncu.search.oil.depthFirstSearch;
import cn.hncu.search.oil.common.Bucket;
import cn.hncu.search.oil.common.MyStack;
import cn.hncu.search.oil.common.NodeOfBucket;
/*
* 题目:
* 有一位厨师要从盛12斤油(a桶)的桶中倒出6斤油来,
* 可是手边只有盛8斤油(b桶)和盛5斤油(c桶)的两个桶,
* 问如何操作才能将6斤取出来呢?
* 题意分析:
* 把三个桶当做一个结点看,
* 每一个结点有三个桶,
* 三个同有9种倒油方法,
* 这个只要把三个桶看成三个节点,
* 以邻接矩阵保存就可以遍历了,
* 其中自己不能倒向自己,
* 及i!=j就可以搞定了。
* 注意:
* 这道题不能弹栈,
* 不然会陷入死循环。
*/
public class DumpOilDFS {
static int count = 0;
public static void main(String[] args) {
/*
* 这个题目只有三个桶我就只newsan个桶了。
*/
Bucket[] bts = new Bucket[3];
bts[0] = new Bucket(12, 12);
bts[1] = new Bucket(8, 0);
bts[2] = new Bucket(5, 0);
NodeOfBucket nb = new NodeOfBucket(bts);// nb = NodeOfBucket
MyStack ms = new MyStack();
depthFirstSearch(nb, ms);
}
static void printAnswer(NodeOfBucket nb) {
if (nb.parent == null) {
return;
}
printAnswer(nb.parent);
System.out.println(nb);
}
/*
* depthFirstSearch-深度优先搜索
* MyGather=mg我的集合
* nb=NodeOfBucket桶的结点
*/
private static void depthFirstSearch(NodeOfBucket nb, MyStack ms) {
/*
* 鸿沟
* 只要任意一个桶装入6升油就可以了。
*/
for (int i = 0; i < nb.bts.length; i++) {
if (nb.bts[i].now == 6) {
/*
* 输出答案
*/
System.out.println("答案出来吧!");
printAnswer(nb);
return;
}
}
/*
* 将该搜索点加入集合
*/
ms.push(nb);
/*
* i表示第i个桶
* j表示第j个桶
* 合起来用就表示第i个桶的油倒入第j个桶中。
*/
for (int i = 0; i < nb.bts.length; i++) {
for (int j = 0; j < nb.bts.length; j++) {
// 相同的桶不到油
if (i == j) {
continue;
}
/*
* iCanOutNum表示第i个桶可以倒出iCanOutNum数量的油
*/
int iCanOutNum = nb.bts[i].canOut();
int jCanInNum = nb.bts[j].canIn();
// i桶已近没有油了
if (iCanOutNum <= 0) {
continue;
}
// j该桶已近满了,不能再倒入油了
if (jCanInNum <= 0) {
continue;
}
/*
* J桶只能倒入的数量
*/
NodeOfBucket nb1 = new NodeOfBucket(nb);
if (jCanInNum <= iCanOutNum) {
/*
* 新的结点中,
* j只能倒入jCanInNum数量的油
* i就只倒出jCanInNum数量的油
*/
nb1.bts[j].in(jCanInNum);
nb1.bts[i].out(jCanInNum);
} else {
/*
* 新的结点中,
* j只能倒入iCanOutNum数量的油
* i就只倒出iCanOutNum数量的油
*/
nb1.bts[j].in(iCanOutNum);
nb1.bts[i].out(iCanOutNum);
}
// 重复倒油过程,会形成死循环的。
if (ms.contain(nb1)) {
continue;
}
nb1.parent = nb;
depthFirstSearch(nb1, ms);
/*
* 回退只要弹出nb1就可以了
*/
nb1.parent = null;
}
}
}
}
------