问题介绍:
在河的左岸有N个传教士、N个野人和一条船,传教士们想用这条船把所有人都运过河去,但有以下条件限制:
(1)修道士和野人都会划船,但船每次最多只能运K个人;
(2)在任何岸边以及船上,野人数目都不能超过修道士,否则修道士会被野人吃掉。
假定野人会服从任何一种过河安排,请规划出一个确保修道士安全过河的计划。
问题分析:
因为船的承载能力有限,所以船上载人过河的方案有限,首先把所有的过河时合理的过河过程,此外,因为要考虑左岸和右岸都要符合要求,所以要明确两岸的位置状态,为了使整个问题简单化,我们以左岸情况为关注点,运算过程中只要保证右岸符合条件即可。在左岸状态下,搜索在当前状态下,经过合法的过程后,依然使左岸、右岸保持合法的状态。我这里采用递归的深度遍历思想,在找到目标状态后,回溯到当前函数的上一层,继续推算其他的情况,直到所有情况完全遍历,结束搜索。在深度遍历的过程中,使用栈Merge来存储需要遍历的状态节点,同时把所有此状态经过合法过程到达的合法状态放入栈Merge中,进行递归,递归函数最后将此层递归的状态出栈。当搜索到目标状态后,把整个状态栈存放到一个存放遍历路径的数组MergeList中,即为一条遍历路径。当搜索结束后,可以通过MergeList数组找出所有的最优路径。
需要的实体类有:
public class Status {
private int joeNum = 0; //传教士数量
private int wildNum = 0; //野人数量
private int position = 0; //船所在的位置,0位于左岸,1位于右岸
-----------------------------------------------
public Status(int j,int w,int p){} //构造方法
public int getJoeNum(){} //获取传教士人数
public int getWildNum(){} //获取野人人数
public int getPosition(){} //获取船的位置
public boolean isSame(Status s){} //判断两个状态是否完全一致
public boolean isSafe(Process process){} //经过传入的过程后,是否能使左岸、右岸处于安全状态
}
Public class Process {
private int position = 0; //船的位置
private int joeNum = 0; //传教士数目
private int wildNum = 0; //野人数目
public Process(int p,int j,int w){} //构造方法
public int getPosition(){} //获取船的位置
public int getJoeNum(){} //获取传教士数目
public int getWildNum(){} //获取野人数目
}
public class Merge {
private Status status;
private Process process;
-----------------------------------------------
public Merge(Status status,Process process){} //构造方法
public Status getStatus(){} //获得该节点中的状态
public void setStatus(Status status){} //设置该节点的状态
public Process getProcess(){} //获得该节点的操作
public void setProcess(Process process){} //设置该节点的操纵
}
public class Project {
private ArrayList> mergeList = new ArrayList>(); //用于存储所有找到的可行路径,从其中找到最优路径
private ArrayList merge = new ArrayList(); //用于遍历过程中存放遍历路径
private ArrayList best = new ArrayList(); //存放最优路径
private ArrayList statusList = new ArrayList(); //存放所有状态
private ArrayListprocessList = new ArrayList(); //存放所有过程
public static int joe = 0,wild = 0,content = 0,max = 10000,num = 1; //基本信息初始化
private Status oriStatus,aimStatus; //原始状态和目标状态对象
---------------------------------------------------------------------------------------------------------------------------------
public static void main(String args[]){} //主函数,程序入口
public Project(String args[]){} //构造方法,参数为运行时附带输入的参数
public void getBaseData(String args[]){} //获得基本的数据,将字符转化为int型,并实例化初始状态,目标状态对象
public void setProcessList(){ //产生所有可能的操作
//System.out.println(i +" "+j + "
public boolean check(Status sta){} //检测传入的状态是否已经遍历过了
public void print(ArrayListmer){} //打印结果
public void copy(ArrayListbest,ArrayList merge){} //将已经找到的结果拷贝给best放入结果链表中
public void Looking(){
while(!merge.isEmpty()){ //如果Merge不为空,则说明没有完全遍历
status = merge.get(merge.size()-1).getStatus(); //获得要遍历的状态
if(status.isSame(aimStatus)) { //如果是目标状态
ArrayList mer = new ArrayList(); //将遍历过程放入mer中
mergeList.add(mer); //将所有可能的结果放入结果集
merge.remove(merge.size()-1); //此状态出栈
for(int i = 0;i < processList.size();i ++){ //当前状态不是目标状态
if(status.isSafe(processList.get(i))&&status.getPosition() == 0){ //检测经过该操作后是否还是安全状态,且该状态是左岸
Status sta = newStatus(status.getJoeNum()-processList.get(i).getJoeNum(),status.getWildNum()-processList.get(i).getWildNum(),1); //用于保存经过这个操作后变成的状态
if(check(sta)){ //检测这个状态是否已经经历过
merge.add(new Merge(sta,processList.get(i))); //加入遍历队列
Looking(); //进行下一层遍历
if(status.isSafe(processList.get(i))&&status.getPosition() == 1){ //当前状态不是目标状态
Status sta = new Status(status.getJoeNum()+processList.get(i).getJoeNum(),status.getWildNum()+processList.get(i).getWildNum(),0);//检测经过该操作后是否还是安全状态,且该状态是左岸
if(check(sta)){ //检测这个状态是否已经经历过
merge.add(new Merge(sta,processList.get(i))); //加入遍历队列
Looking(); //进行下一层遍历
merge.remove(merge.size()-1); //出栈
public void clear(){} //系统最后的结果输出