zoukankan      html  css  js  c++  java
  • 狼羊过河问题

    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

  • 相关阅读:
    使用sshfs挂载远程服务器目录
    yum install --downloadonly 下载依赖包到本地 但不安装
    CentOS 7安装SSHFS 实现远程主机目录 挂载为本地目录
    CentOS7下FTP的安装与配置
    标签传播算法(Label Propagation Algorithm, LPA)初探
    线性模型(linear model)基本定义及参数求解数学本质、损失函数的选择与评估数学原理、及其基于线性模型衍生的其他机器学习模型相关原理讨论
    贝叶斯A/B测试
    谨慎选择我们的先验
    关于年会抢红包游戏的一个思考
    WMI攻击技术研究
  • 原文地址:https://www.cnblogs.com/chaohi/p/2330330.html
Copyright © 2011-2022 走看看