狼羊过河问题

package guohe;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * 狼羊过河问题
 * @author tiger
 * @date 2011年1月27日。
 *
 * 这里是用面向对象的编程方式,有定义了狼和羊两个类。
 * 但其实程序里并没有用到它们的行为,该问题只是关心它们的数目而已!
 * 所以其实可以直接就定义四个变量来存储两岸的狼数和羊数,然后在遍历
 * 递归的同时增减这四个数字即可。
 *
 */
public class Guohe {

 //左岸的狼数和羊数
 private List<Actor> leftLangs = new LinkedList<Actor>();
 private List<Actor> leftYangs = new LinkedList<Actor>();
 
 //右岸的狼数和羊数
 private List<Actor> rightLangs = new LinkedList<Actor>();
 private List<Actor> rightYangs = new LinkedList<Actor>();
 
 //存储所有成功过河的方案
 private List winSteps = new ArrayList();
 
 public Guohe() {
  init();
 }
 
 /**
  * 刷新重置盘面为初始情况
  */
 private void init() {
  leftLangs.clear();
  leftYangs.clear();
  rightLangs.clear();
  rightYangs.clear();
  for (int i = 0; i < 3; i++) {
   leftLangs.add(new Lang());
   leftYangs.add(new Yang());
  }
  
  //这两个状态需要初始放进去。
  states.add("3,3,0,0,1");
  states.add("3,3,0,0,2");
  
  //方向设为初始向对岸的方向
  fangxiang = TYPE_FANGXIANG_GO;
 }
 
 
 //到对岸:go , 回来:come
 private static int TYPE_FANGXIANG_GO = 1;
 private static int TYPE_FANGXIANG_COME = 2;
 //船行方向
 private int fangxiang = TYPE_FANGXIANG_GO;
 
 /**
  * 保存盘面的状态
  *
  * 保存的是有5个数字的字符串,这5个数字代表的意义依次是:
  * 左岸狼数、左岸羊数、右岸狼数、右岸羊数、当前船行方向。
  *
  * 状态的保存非常重要,把所有递归遍历遇到的状态都保存在这里,
  * 当后面的某次遍历所遇到的盘面已经有在states里存在的话,说明该
  * 盘面已经被处理过,则可以直接跳过。
  *
  * 保存下已经处理过的盘面,这样的设计可以防止出现死循环导致内存泄露。
  */
 private List states = new ArrayList();
 
 
 /**
  * 针对当前船行方向,根据当前盘面情况,即两岸的狼数和羊数
  * 得到可以上船的狼数和羊数。 该方法中会把盘面状态保存入states.
  * @param fangxiang
  * @return
  */
 private List<int[]> getChuanMember(int fangxiang)
 {
  List<int[]> rtnlist = new LinkedList<int[]>();
  String key = "";
  
  List alangs, ayangs, blangs, byangs;
  if(fangxiang == TYPE_FANGXIANG_GO)
  {
   alangs = leftLangs;
   ayangs = leftYangs;
   blangs = rightLangs;
   byangs = rightYangs;
  }else{
   alangs = rightLangs;
   ayangs = rightYangs;
   blangs = leftLangs;
   byangs = leftYangs;
  }
  
  //判断 1,0 .(1狼0羊)
  if(alangs.size() >= 1)
  {
   if((alangs.size() - 1 <= ayangs.size() || ayangs.size() == 0) && (blangs.size() + 1 <= byangs.size() || byangs.size() == 0))
   {
    if(fangxiang == TYPE_FANGXIANG_GO)
    {
     key = (alangs.size() - 1) + "," + ayangs.size() + "," + (blangs.size() + 1) + "," + byangs.size() + "," + TYPE_FANGXIANG_GO;
    }else{
     key = (blangs.size() + 1) + "," + byangs.size() + "," + (alangs.size() - 1) + "," + ayangs.size() + "," + TYPE_FANGXIANG_COME;
    }
    
    if(!states.contains(key))
    {
     rtnlist.add(new int[]{1, 0});
     states.add(key);
    }
   }
  }
  
  //判断 2,0 .(2狼0羊)
  if(alangs.size() >= 2)
  {
   if((alangs.size() - 2 <= ayangs.size() || ayangs.size() == 0) && (blangs.size() + 2 <= byangs.size() || byangs.size() == 0))
   {
    if(fangxiang == TYPE_FANGXIANG_GO)
    {
     key = (alangs.size() - 2) + "," + ayangs.size() + "," + (blangs.size() + 2) + "," + byangs.size() + "," + TYPE_FANGXIANG_GO;
    }else{
     key = (blangs.size() + 2) + "," + byangs.size() + "," + (alangs.size() - 2) + "," + ayangs.size() + "," + TYPE_FANGXIANG_COME;
    }
    
    if(!states.contains(key))
    {
     rtnlist.add(new int[]{2, 0});
     states.add(key);
    }
   }
  }
  
  //判断0,1 .(0狼1羊)
  if(ayangs.size() >= 1)
  {
   if((alangs.size() <= ayangs.size() - 1 || ayangs.size() - 1 == 0) && (blangs.size() <= byangs.size() + 1 || byangs.size() + 1 == 0))
   {
    if(fangxiang == TYPE_FANGXIANG_GO)
    {
     key = alangs.size() + "," + (ayangs.size() - 1) + "," + blangs.size() + "," + (byangs.size() + 1) + "," + TYPE_FANGXIANG_GO;
    }else{
     key = blangs.size() + "," + (byangs.size() + 1) + "," + alangs.size() + "," + (ayangs.size() - 1) + "," + TYPE_FANGXIANG_COME;
    }
    
    if(!states.contains(key))
    {
     rtnlist.add(new int[]{0, 1});
     states.add(key);
    }
   }
  }
  //判断0,2 .(0狼2羊)
  if(ayangs.size() >= 2)
  {
   if((alangs.size() <= ayangs.size() - 2 || ayangs.size() - 2 == 0) && (blangs.size() <= byangs.size() + 2 || byangs.size() + 2 == 0))
   {
    if(fangxiang == TYPE_FANGXIANG_GO)
    {
     key = alangs.size() + "," + (ayangs.size() - 2) + "," + blangs.size() + "," + (byangs.size() + 2) + "," + TYPE_FANGXIANG_GO;
    }else{
     key = blangs.size() + "," + (byangs.size() + 2) + "," + alangs.size() + "," + (ayangs.size() - 2) + "," + TYPE_FANGXIANG_COME;
    }
    
    if(!states.contains(key))
    {
     rtnlist.add(new int[]{0, 2});
     states.add(key);
    }
   }
  }
  
  //判断1,1 .(1狼1羊)
  if(alangs.size() >= 1 && ayangs.size() >= 1)
  {
   if((alangs.size() - 1 <= ayangs.size() - 1 || ayangs.size() - 1 == 0) && (blangs.size() + 1 <= byangs.size() + 1 || byangs.size() + 1 == 0))
   {
    if(fangxiang == TYPE_FANGXIANG_GO)
    {
     key = (alangs.size() - 1) + "," + (ayangs.size() - 1) + "," + (blangs.size() + 1) + "," + (byangs.size() + 1) + "," + TYPE_FANGXIANG_GO;
    }else{
     key = (blangs.size() + 1) + "," + (byangs.size() + 1) + "," + (alangs.size() - 1) + "," + (ayangs.size() - 1) + "," + TYPE_FANGXIANG_COME;
    }
    
    if(!states.contains(key))
    {
     rtnlist.add(new int[]{1, 1});
     states.add(key);
    }
   }
  }
  return rtnlist;
 }
 
 /**
  * 用来存储当前遍历的方案步骤
  *
  * 存储的是大小为3的数字数组。各元素的意义依次是:
  * 船行方向、船上狼数、船上羊数
  *
  */
 private List<int[]> temp = new ArrayList<int[]>();
 
 /**
  * 递归方法,不断深度遍历
  */
 private void digui()
 {
  //得到当前盘面下,可以上船的狼数和羊数
  List list = this.getChuanMember(fangxiang);
  
  //如果找不到可乘船的狼羊,则说明当前的盘面无法走向成功,则退出。
  if(list.isEmpty())
  {
   //重置为初始盘面情况
   init();
   //清空之前的步骤存储
   temp.clear();
   return;
  }
  for (int i = 0; i < list.size(); i++) {
   int[] element = (int[]) list.get(i);
   
   if(fangxiang == TYPE_FANGXIANG_GO)
   {    
    //修改两岸的狼数
    if(element[0] == 1)
    {     
     Actor a = this.leftLangs.remove(0);
     this.rightLangs.add(a);
    }
    else if(element[0] == 2)
    {
     Actor a = this.leftLangs.remove(0);
     this.rightLangs.add(a);
     a = this.leftLangs.remove(0);
     this.rightLangs.add(a);
    }
    //修改两岸的羊数
    if(element[1] == 1)
    {     
     Actor a = this.leftYangs.remove(0);
     this.rightYangs.add(a);
    }
    else if(element[1] == 2)
    {
     Actor a = this.leftYangs.remove(0);
     this.rightYangs.add(a);
     a = this.leftYangs.remove(0);
     this.rightYangs.add(a);
    }
    
    //存储步骤
    temp.add(new int[]{fangxiang, element[0], element[1]});
    //判断是否完成,如果完成,将完成步骤加入完成方案的列表里
    if(this.success())
    {
     //打印成功方案
     System.out.println("方案:(共" + temp.size() + "步)");
     for (int j = 0; j < temp.size(); j++) {
      int[] a = (int[]) temp.get(j);
      System.out.println("第" + (j + 1) + "步, " + (a[0] == 1 ? "前进" : "后退") + "---> 狼" + a[1] + ",羊" + a[2]);
     }
     winSteps.add(temp);
     
     //重置盘面为初始情况
     init();
     //清空之前的步骤存储
     temp.clear();
     return; //这里是return而非continue,是因为既然已经成功了,而当前是最后一步,那么后面的循环必然不能成功。--->不大肯定。
    }
    fangxiang = TYPE_FANGXIANG_COME;
    digui();
   }
   else if(fangxiang == TYPE_FANGXIANG_COME)
   {    
    //修改两岸的狼数
    if(element[0] == 1)
    {     
     Actor a = this.rightLangs.remove(0);
     this.leftLangs.add(a);
    }
    else if(element[0] == 2)
    {
     Actor a = this.rightLangs.remove(0);
     this.leftLangs.add(a);
     a = this.rightLangs.remove(0);
     this.leftLangs.add(a);
    }
    //修改两岸的羊数
    if(element[1] == 1)
    {     
     Actor a = this.rightYangs.remove(0);
     this.leftYangs.add(a);
    }
    else if(element[1] == 2){
     Actor a = this.rightYangs.remove(0);
     this.leftYangs.add(a);
     a = this.rightYangs.remove(0);
     this.leftYangs.add(a);
    }
    //存储步骤
    temp.add(new int[]{fangxiang, element[0], element[1]});
    //调换方向
    fangxiang = TYPE_FANGXIANG_GO;
    //递归处理现在的盘面
    digui();
   }
  }
 }
 
 
 private boolean success()
 {
  return this.leftLangs.isEmpty() && this.leftYangs.isEmpty() && this.rightLangs.size() == 3 && this.rightYangs.size() == 3;
 }
 
 
 
 public static final int TYPE_LANG = 1;
 public static final int TYPE_YANG = 2;
 class Actor {
  public int type = 0;
  public boolean isLang()
  {
   return type == TYPE_LANG;
  }
  public boolean isYang()
  {
   return type == TYPE_YANG;
  }
 }
 //狼
 class Lang extends Actor{
  public Lang() {
   type = TYPE_LANG;
  }
 }
 //羊
 class Yang extends Actor{
  public Yang() {
   type = TYPE_YANG;
  }
 }
 
 public static void main(String[] args) {
  new Guohe().digui();
 }
 
}

 

打印结果如下:

方案:(共11步)
第1步, 前进---> 狼2,羊0
第2步, 后退---> 狼1,羊0
第3步, 前进---> 狼2,羊0
第4步, 后退---> 狼1,羊0
第5步, 前进---> 狼0,羊2
第6步, 后退---> 狼1,羊1
第7步, 前进---> 狼0,羊2
第8步, 后退---> 狼1,羊0
第9步, 前进---> 狼2,羊0
第10步, 后退---> 狼1,羊0
第11步, 前进---> 狼2,羊0

 

posted on 2011-02-11 09:57  台哥编程课堂  阅读(1022)  评论(0编辑  收藏  举报

导航