有4个红酒瓶子,它们的容量分别是:9升, 7升, 4升, 2升
开始的状态是 [9,0,0,0],也就是说:第一个瓶子满着,其它的都空着。
允许把酒从一个瓶子倒入另一个瓶子,但只能把一个瓶子倒满或把一个瓶子倒空,不能有中间状态。
这样的一次倒酒动作称为1次操作。
假设瓶子的容量和初始状态不变,对于给定的目标状态,至少需要多少次操作才能实现?
本题就是要求你编程实现最小操作次数的计算。
输入:最终状态(空格分隔)
输出:最小操作次数(如无法实现,则输出-1)
例如:
输入:
9 0 0 0
应该输出:
0
输入:
6 0 0 3
应该输出:
-1
输入:
7 2 0 0
应该输出:
开始的状态是 [9,0,0,0],也就是说:第一个瓶子满着,其它的都空着。
允许把酒从一个瓶子倒入另一个瓶子,但只能把一个瓶子倒满或把一个瓶子倒空,不能有中间状态。
这样的一次倒酒动作称为1次操作。
假设瓶子的容量和初始状态不变,对于给定的目标状态,至少需要多少次操作才能实现?
本题就是要求你编程实现最小操作次数的计算。
输入:最终状态(空格分隔)
输出:最小操作次数(如无法实现,则输出-1)
例如:
输入:
9 0 0 0
应该输出:
0
输入:
6 0 0 3
应该输出:
-1
输入:
7 2 0 0
应该输出:
2
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;
public class Test {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String last = input.nextLine();
Set<String> init = new HashSet<String>();
init.add("9 0 0 0");
Set<String> hist = new HashSet<String>();
hist.addAll(init);
int r = bfs(hist,init,last);
System.out.println(r);
}
//hist 记录历史状态
//init 现在这一层所有状态
public static int bfs(Set<String> hist,Set<String> init,String goStr){
//这一层有我想要的结果
if(hist.contains(goStr))return 0;
//下一层的倒酒姿势
Set<String> form = new HashSet<String>();
for (Iterator<String> iterator = init.iterator(); iterator.hasNext();) {
String next = iterator.next();
Set<String> newForm = move(next);
form.addAll(newForm);
}
//消除重复倒酒姿势
form.removeAll(hist);
//如果消除重复倒酒姿势后大小 为 0 说明没有可以用的姿势了 -1 代表失败的意思,找不到结果
if(form.isEmpty())return -1;
//载入历史倒酒姿势
hist.addAll(form);
//递归调用 bfs 扩散开树的下一层开始宽度优先遍历
int r = bfs(hist,form,goStr);
//出现失败情况
if(r<0)return -1;
//否则 倒酒次数加1 返回回去
return 1+r;
}
public static Set<String> move(String init){
int[] cap = {9,7,4,2};
int[] data = new int[4];
String[] ss = init.split(" ");
Set<String> set = new HashSet<String>();
for(int i=0;i<ss.length;i++){
data[i] = Integer.parseInt(ss[i]);
}
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(i==j)continue;
//A酒杯没酒了
if(data[i]==0)continue;
//B酒杯满了
if(data[j]==cap[j])continue;
//A 全倒进 B 的总酒量
int sumWine = data[i] + data[j];
//待会即将被改变的状态
int[] temp = Arrays.copyOf(data,data.length);
//B酒杯装完全部A
if(sumWine<=cap[j]){
temp[i] =0;
temp[j] = sumWine;
}else{
//B酒杯不可以装满全部A
temp[i] = sumWine - cap[j];
temp[j] = cap[j];
}
String res = "";
for(int k=0;k<4;k++){
res += " "+temp[k];
}
set.add(res.trim());
}
}
return set;
}
}