一、问题描述
给定两个水壶,一个可以装4升水,一个能装3升水,水壶上没有任何度量标记。有一水龙头可以用来往壶中灌水。问题是怎样在能装4升的水壶里面恰好只装2升水。
二、解决方法
1.定义状态空间
用(x,y)两个有序整数表示状态空间的一个状态,
x表示4L水壶中的水量,x∈[0,4],
y表示3L水壶中的水量,y∈[0,3]。
初始状态为(0,0),目标状态为(2,0)
2.确定一组操作
①x倒满(x=4)
②y倒满(y=3)
③x倒空(x=0)
④y倒空(y=0)
⑤y倒入x(y->x)
⑥x倒入y(x->y)
3.搜索过程
不是很复杂,我就不画流程图了
整体的思路为深度优先搜索,主要通过栈和递归来实现
首先对状态空间进行初始化,设置第一个节点的状态为已访问,并放入栈中
然后通过递归进行深度优先搜索
对每个节点进行六种操作,接着查重,将符合要求的子节点入栈,不断循环,直到x=2,找到目标状态,此时栈中存放的就是一条解决方案,然后我们将其输出
之后重复这个步骤,直到遍历完所有的路径,递归结束
三、代码实现
1.关键代码
首先我用了一个内部类来记录水壶的状态
//声明一个内部类用来记录水壶的状态
class WaterState {
int x4;
int y3;
int step;//记录进行的是哪一步操作
//构造器
WaterState(int x4, int y3, int step) {
this.x4 = x4;
this.y3 = y3;
this.step = step;
}
}
深度优先遍历
//深度优先遍历
void dfs(int x4, int y3) {
if (x4 == 2) {
Output(pos);
pos++;
}
else {
for (int i = 1; i <= 6; i++) {//依次进行六种操作
WaterState waterState = operate(x4, y3, i);//返回操作后水壶的状态
if (checkRepeat(waterState.x4, waterState.y3) == 0) {//查重
pathStack.add(waterState);//入栈
space[waterState.x4][waterState.y3] = 1;//设置为已访问
dfs(waterState.x4, waterState.y3);//递归
pathStack.pop();//出栈
space[waterState.x4][waterState.y3] = 0;//状态重置
}
}
}
}
2.全部代码
import java.util.Stack;
public class MyPot {
int[][] space = new int[5][4];//用一个二维数组来记录水壶是否被访问
Stack<WaterState> pathStack = new Stack();
int pos = 1;//记录第几种解法
public static void main(String[] args) {
MyPot pot = new MyPot();
}
//初始化类
public MyPot() {
initSpace();
space[0][0] = 1;//初始状态设置为已访问
pathStack.add(new WaterState(0, 0, 0));
dfs(0, 0);
}
//输出
void Output(int pos) {
System.out.println("第"+pos+"种解决方案:");
System.out.println("4升水壶 3升水壶 所使用的操作");
int i = 0;
int l = pathStack.size();
while (l>0) {
System.out.println(pathStack.get(i).x4 + " " + pathStack.get(i).y3 + " " + pathStack.get(i).step);
i++;
l--;
}
System.out.println();
}
//深度优先遍历
void dfs(int x4, int y3) {
if (x4 == 2) {
Output(pos);
pos++;
}
else {
for (int i = 1; i <= 6; i++) {//依次进行六种操作
WaterState waterState = operate(x4, y3, i);//返回操作后水壶的状态
if (checkRepeat(waterState.x4, waterState.y3) == 0) {//查重
pathStack.add(waterState);//入栈
space[waterState.x4][waterState.y3] = 1;//设置为已访问
dfs(waterState.x4, waterState.y3);//递归
pathStack.pop();//出栈
space[waterState.x4][waterState.y3] = 0;//状态重置
}
}
}
}
//实现六种操作
WaterState operate(int x4, int y3, int i) {
switch (i) {
case 1:
x4 = 4;
break;
case 2:
y3 = 3;
break;
case 3:
x4 = 0;
break;
case 4:
y3 = 0;
break;
case 5://x->y
if (x4 + y3 > 3) {
x4 = x4 + y3 - 3;
y3 = 3;
} else {
y3 = x4 + y3;
x4 = 0;
}
break;
case 6://y->x
if (x4 + y3 > 4) {
y3 = x4 + y3 - 4;
x4 = 4;
} else {
x4 = x4 + y3;
y3 = 0;
}
break;
default:
break;
}
//创建一个WaterState对象返回
return new WaterState(x4, y3, i);
}
//查重
int checkRepeat(int x4, int y3) {
if (space[x4][y3] == 1) {
return 1;
}
return 0;
}
//状态空间初始化
void initSpace() {//所有状态初始为0(即未访问)
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 4; j++) {
space[i][j] = 0;
}
}
}
//声明一个内部类用来记录水壶操作的状态
class WaterState {
int x4;
int y3;
int step;//记录进行的是哪一步操作
WaterState(int x4, int y3, int step) {
this.x4 = x4;
this.y3 = y3;
this.step = step;
}
}
}
四、运行结果
总结
希望我的文章能够帮助到你