您的位置:首页 > 其它

状态树搜索算法-------------抽象问题与建模思想(三只水桶分水问题)

2016-04-05 00:35 471 查看
我的天!!!!!!!!!!!!!!!!!!!!!!!

我终于把这该死的三个水桶把水分成两半了!!!!!!!!!!!!

今天我用下午和晚上的时间研究用三个水桶8L,5L,3L把8L水分成两份(4L)

晚上我从八点种时间开始写算法,写了4个小时,除了其中半个小时的洗澡,我一直在想,该如何实现。。。。。。

其中被那个备忘录卡了我一个半小时!!!!!!!!(谢天谢地,我终于把它搞出来了,现在我欣喜的心情无以复加!!!!!!!!!!)

好了,情感发泄完了,该步入正题了,总结我今天的算法学习。

今天看《算法的乐趣》第五章,作者提出问题:把三桶个水桶等分8升水的问题,有8,5,3L的水桶分8升水,最后的结果要在8L水桶和5L水桶中分别有4L水。

首先要定义问题的解,并分析解空间范围和拓扑结构,然后根据解空间的范围和拓扑结构设计遍历搜索算法。

建立数学模型,根节点为初始状态,叶子节点可能是最终状态,也可能是某个无法转换的最终中间状态,有多少个最终状态叶子节点就要多少种答案。

现在是12点17分,室友在聊天,可能会打错几个字,大家不要介意。

状态的数学模型与状态树:状态的数学模型可以用一个一维数组存放,状态树就是建立起节点与节点之间的联系。

倒水动作的数学模型:合法的倒水动作包含3个要素:倒出水的桶、接收水的桶、倒水的体积。{from,to,water}

搜索算法:确定状态树模型后,第二个重要的问题是:状态树的搜索算法。

可用深度优先也可以广度优先,我写的是深度优先。

状态树的搜索就是对整个树进行遍历,其中还暗含了状态的生产。

状态树的剪枝和重复状态的判断

为了避免状态树的重复和环形死循环,一定要有备忘录。

我就是在处理备忘录的时候没有理解作者的思想,所以出了bug。

后来我用往前遍历,终于成功解决了,得出了16个答案,但是时间原因,我就不写输出过程的算法了。

下面是我的实现代码:

主类,创建状态树对象,传入一个根节点

package 状态数搜索算法;

public class Main {
public static void main(String[] args) {
Main ma = new Main();
ma.initMain();
}
public void initMain(){
DumpWater dw = new DumpWater();
int[] str = {8,0,0};
StateNode state = new StateNode(str);
dw.SearchState(state);
}
}


递归倒水算法:

package 状态数搜索算法;

import java.util.Vector;

public class DumpWater {
public int count = 0;
public void SearchState(StateNode state){//检查每一个状态是否是最终状态,不是的话就继续检索
if(state.IsFinalState()){//判断节点是否为最终状态
count++;
System.out.println(count+":"+"Succeed!");
return ;
}
for(int j=0;j<state.bucket.length;j++){
for(int i=0;i<state.bucket.length;i++){
SearchStateAction(state, i, j);
}
}
}
public void SearchStateAction(StateNode state,int from,int to){
if(state.CanTakeDumpAction(from, to)){//判断当前状态能否倒水
StateNode next = new StateNode(state.bucket);
next.back = state;
boolean bDump = state.Dump_Wate(from, to, next);
if( bDump && !Tool.IsProcessedState(next) ){
SearchState(next);
}
}
}

}


状态树节点:

package 状态数搜索算法;

public class StateNode {//水桶节点
public int[] bucket = new int[3];//水桶
public StateNode back;
public int getMax(int bucket){
if( bucket == 0 ){
return 8;
}else if( bucket == 1 ){
return 5;
}else if( bucket == 2 ){
return 3;
}
return 0;
}
public StateNode(int[] str){
this.bucket[0] = str[0];
this.bucket[1] = str[1];
this.bucket[2] = str[2];
}
public boolean Dump_Wate(int from,int to,StateNode next){
int dump_Water = next.getMax(to) - next.bucket[to];
//		System.out.println(from+"倒去"+to+"  dump_Water-- >"+dump_Water);
if( next.bucket[from] >= dump_Water ){
next.bucket[to] = next.bucket[to] + dump_Water;
next.bucket[from] = next.bucket[from] - dump_Water;
}else{
next.bucket[to] = next.bucket[to] + next.bucket[from];
dump_Water = next.bucket[from];
next.bucket[from] = 0;
}
if( dump_Water > 0 ){
next.SetAction(dump_Water, from, to,next);
return true;
}
return false;
}

public boolean IsFinalState(){
if( bucket[0] == 4 && bucket[1] == 4 && bucket[2] == 0){//判断是否为最终状态
return true;
}else{
return false;
}
}
/**
* 判断水桶编号是否在012
* from 和 to 不相同
* from没满,to不为空
* @param from
* @param to
* @return
*/
public boolean CanTakeDumpAction(int from,int to){
if( from>=0 && from<3 && to>=0 && to<3 ){//判断水桶编号是否在0、1、2中
if( (from != to) &&
IsBucketEmpty(from)
&& IsBucketFull(to)){//倒水水桶不是自己,倒水水桶没空,被倒水桶不满,可以倒
return true;
}
}
return false;
}
/**
* 判断水桶是否为空
* 有水就返回true
* 空就返回false
* @param from
* @return
*/
public boolean IsBucketEmpty(int from){//判断倒水的桶是否为空
if(bucket[from] > 0){//如果水桶有水,返回true
return true;
}else{
return false;//空返回false
}
}
/**
* 判断水桶是否已经装满
* 如果满了,返回false
* 如果可以装就返回true
*/
public boolean IsBucketFull(int to){//判断被倒水的水桶是否已满
if(to == 0 && bucket[to]<8 && bucket[to]>=0 ){//如果水桶是一号,水量大于0且小于8,没满,返回true
return true;
}else if(to == 1 && bucket[to]<5 && bucket[to]>=0 ){//2号水桶,水量大于0小于8,没满,返回true
return true;
}else if(to == 2 && bucket[to]<3 && bucket[to]>=0 ){//3号水桶,水量大于0小于3,没满,返回true
return true;
}
return false;
}
/**
* ???
* @param dump_Water
* @param from
* @param to
* @param next
*/
public void SetAction(int dump_Water,int from,int to,StateNode next){

}
public String getText(StateNode state){
String s1 = Integer.toString(state.bucket[0]);
String s2 = Integer.toString(state.bucket[1]);
String s3 = Integer.toString(state.bucket[2]);
String s = s1 + s2 + s3;
return s;
}
}
工具类:

package 状态数搜索算法;

import java.util.HashMap;
import java.util.Vector;

public class Tool {
public static Vector<String> vector = new Vector<String>();
public static boolean IsProcessedState(StateNode state){
StateNode current = state ;
while( state.back != null ){//逐一对比当前状态跟上面状态
if(current.getText(current).contains(state.back.getText(state.back))){
return true;
}
state = state.back;
}

return false;
}

}




这个算法作者用C++做的,我用java实现。

下面是作者的博客,跟书上差不多,大家参考。
http://blog.csdn.net/orbit/article/details/6596521
十二点半了,我该下了。明天有课
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: