試題
代碼
考慮從上一狀態轉換到下一狀態有三種方法:
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);
}
}