试题
代码
考虑从上一状态转换到下一状态有三种方法:
1、往某个桶加水
2、倒掉某桶的水
3、将一个桶的水往另一个桶里倒
使用宽度优先搜索:
1、一旦找到结果必然是最优结果,求解最少次数。
2、有助剪枝,当log中保存的状态一旦已经尝试过肯定无需继续尝试。
import java.util.*;
class Main{
public static void main(String[] args){
int[] bucket = new int[3];
int[] water = new int[]{3, 5, 8};
int target = 4;
int step = 0;
int[][] shift = new int[][]{
{0,1},{0,2},
{1,0},{1,2},
{2,0},{2,1},
};
HashSet<String> log = new HashSet<>();
Queue<int[]> queue = new LinkedList<>();
queue.offer(bucket);
while(!queue.isEmpty()){
int size = queue.size();
for(int q=0; q<size; q++){
bucket = queue.poll();
// System.out.println(Arrays.toString(bucket)+step);
//终止
if (bucket[2] == target || bucket[1] == target ||bucket[0] == target) {
System.out.println(step);
return;
}
String cur_str = Arrays.toString(bucket);
//剪枝
if(log.contains(cur_str)){
continue;
}
log.add(cur_str);
int tmp;
for(int i=0; i<3; i++){
//倒入水
if(bucket[i] < water[i]){
tmp = bucket[i];
bucket[i] = water[i];
queue.offer(bucket.clone());
bucket[i] = tmp;
}
//倒出水
if(bucket[i] != 0){
tmp = bucket[i];
bucket[i] = 0;
queue.offer(bucket.clone());
bucket[i] = tmp;
}
}
//转移水
int f, t, from, to;
for(int[] ss : shift){
f = ss[0];
t = ss[1];
from = bucket[f];
to = bucket[t];
if(from == 0){
continue;
}
int cap = bucket[f] + bucket[t] - water[t];
if(cap <= 0){
bucket[f] = 0;
bucket[t] = from + to;
}else{
bucket[f] = cap;
bucket[t] = water[t];
}
queue.offer(bucket.clone());
bucket[f] = from;
bucket[t] = to;
}
}
step++;
}
System.out.println(-1);
}
}