1. 题目描述:
有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
应该输出:
2
2. ① 分酒,迷宫这些都是没有明显节点的图,不像城市建设网络这样子具有明显的节点,但是它是一种隐式的图,涉及的是状态转移,一个状态经过一次操作可能演变成另外一种状态,利用宽度优先搜索的话可以求解出从原始状态到目标状态需要经历的最少的步骤,宽度优先搜索,把原始状态加入到队列中,在循环中弹出一个加入它的若干个邻居节点(而且题目的提示也很明显,开始状态是什么,最终状态是什么,一次操作从一个状态转换到另外的一个状态,而宽搜就是解决这类问题的:从原始转态到目标状态需要经过的最少的步骤)
因为要求解出经历的最少步骤,所以中间的过程需要记录当前节点的深度,而且需要知道当前节点的内容是什么,所以需要一个内部类来封装这些属性,设置相应的get和set方法,重写一下toString方法以便测试,因为涉及到图的搜索,所以一定要增加一个标志来标记当前的节点是否之前已经被访问过,这里可以使用Set数据结构来进行判断
② 分酒的过程中加入能够把当前的酒倒进另外一个酒杯中那么进行一次导出酒的操作,其中涉及到字符串与整型数组的转换等的细节,在编写完成之后那么调试一下就知道当前的结果是否正确
有两种情况可以倒酒:a:自己能够将酒倒满到别的酒瓶但是自己的酒还有剩 b:自己的酒全部倒给别的酒瓶但是自己的酒没有剩
根据题目的描述怎么样进行倒酒这是最重要的,倒酒的时候需要考虑到一些细节方面的问题,然后根据bfs来进行解决即可
由于没有办法提交代码到平台上,所以不能够判断是否完全正确
3. 代码如下:
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
import java.util.Set;
public class Main {
static Queue<Node> queue = new LinkedList<Node>();
static String s = "9000";
static String input;
static Set<String> set = new HashSet<String>();
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
input = sc.next().replace(",", "");
int res = bfs();
System.out.println(res);
sc.close();
}
private static int bfs() {
int v[] = {9, 7, 4, 2};
Node n = new Node(s, 0);
set.add(s);
queue.add(n);
Node p;
while(!queue.isEmpty()){
p = queue.poll();
String temp = p.val;
if(input.equals(temp)) {
return p.depth;
}
String arr[] = new String[4];
for(int i = 0; i < 4; i++){
arr[i] = temp.charAt(i) + "";
}
int t[] = new int[4];
for(int i = 0; i < arr.length; i++){
t[i] = Integer.parseInt(arr[i]);
}
String str = "";
for(int i = 0; i < 4; i++){
if(t[i] == 0) continue;
for(int j = 0; j < 4; j++){
if(i == j) continue;
if(t[j] != v[j] && t[i] - v[j] + t[j] >= 0){
str = "";
for(int k = 0; k < 4; k++){
if(k == i){
str = str + (t[i] - v[j] + t[j]);
}else if(k == j){
str += v[j];
}else{
str += t[k];
}
}
}
else if(v[i] == t[i] && t[i] + t[j] < v[j]){
str = "";
for(int k = 0; k < 4; k++){
if(k == i){
str += "0";
}else if(k == j){
str = str + (t[i] + t[j]);
}else{
str += t[k];
}
}
}
if(!set.contains(str) && str.length() == 4){
set.add(str);
//应该在上一层的count上加1
queue.add(new Node(str, p.getDepth() + 1));
}
}
}
}
return -1;
}
public static class Node{
String val;
int depth;
public Node(String val, int depth) {
this.val = val;
this.depth = depth;
}
//get方法可以用来获取相应节点的深度
public String getVal() {
return val;
}
public void setVal(String val) {
this.val = val;
}
public int getDepth() {
return depth;
}
public void setDepth(int depth) {
this.depth = depth;
}
@Override
public String toString() {
return "Node [val=" + val + ", depth=" + depth + "]";
}
}
}