首页  ·  知识 ·  编程语言
5只蚂蚁走木棍问题优美的Java非递归解法
网友   http://blog.csdn.net/Radic_Feng/archive/2010/01/13/5187176.aspx  Java  编辑:德仔   图片来源:网络
题目描述: 有一根27厘米的细木杆,在第3厘米、7厘米、11厘米、17厘米、23厘米这五个位置上各有一只
题目描述:
    有一根27厘米的细木杆,在第3厘米、7厘米、11厘米、17厘米、23厘米这五个位置上各有一只蚂蚁。木杆很细,不能同时通过一只蚂蚁。开始时,蚂蚁的头朝左还是朝右是任意的,它们只会朝前走或调头,但不会后退。当任意两只蚂蚁碰头时,两只蚂蚁会同时调头朝反方向走。假设蚂蚁们每秒钟可以走一厘米的距离。编写程序,求所有蚂蚁都离开木杆的最小时间和最大时间。
看到很多人发布了他们的解法, 我觉得都过于复杂并不甚清晰, 以下是我的思路和实现.
1. 思路与建模
*将木杆看成0至27的坐标, 5只蚂蚁分别在3, 7, 11, 17, 23的位置
*创建enum Directory{ Left, Right}
*创建Ant类, 蚂蚁可以爬行(walk), 掉头(shift),  并且如果爬出能把自己从蚂蚁队列中移出去.
*创建Controller类, 给定蚂蚁的初始方向, Controller类可以计算出在这种初始方向下蚂蚁全部爬出需要的时间.
*创建Simulator类, 它给出蚂蚁初始方向的所有组合, 并使用Controller执行得到所有时间, 选择最大值和最小值.
蚂蚁的初始方向不是向左就是向右, 可以用二进制表示. 5只蚂蚁, 2^5=32个组合.
所以, 用0-31的二进制刚好可以表示蚂蚁的初始方向. 使用: Integer.toBinaryString(i), 不够五位的话左填充0至五位, 即可得到的如01010这样的二进制串, 比如0表示向左, 1表示向右, 即可得到蚂蚁的初始方向.
 

2. 实现
在Model包内:
 view plaincopy to clipboardprint?
package cn.dfeng.model;  
 
public enum Direction {  
 
    Left, Right  

package cn.dfeng.model;
public enum Direction {
 Left, Right
}
view plaincopy to clipboardprint?
package cn.dfeng.model;  
 
import java.util.ArrayList;  
 
public class Ant {  
 
    public static final int LENGTH = 27;   
    private int position;  
    Direction direction;  
 
    /* 
     * 在木杆上的蚂蚁队列 
     */ 
    ArrayList<Ant> list;  
      
    public Ant( int p, Direction dir, ArrayList<Ant> list ){  
        this.position = p;  
        this.direction = dir;  
        this.list = list;  
    }  
 
    /** 
     * 蚂蚁行走 
     */ 
    public void walk(){  
          
        if( direction == Direction.Right ){  
            position++;  
        }else{  
            position--;  
        }  
          
        //如果大于最大长度获小于0即视为爬出木杆  
        if( position >= LENGTH || position <= 0 ){  
            list.remove( this );  
        }  
    }  
      
    /** 
     * 蚂蚁调头, 行走一秒后查看自己是不是需要调头 
     */ 
    public void shift(){  
        int index = list.indexOf( this );  
        if( index == 0 && list.size() > 1 ){  
            if( this.position == list.get(1).position ){  
                doShift();  
            }  
        }else if( index == list.size()-1 && index > 0 ){  
            if( this.position == list.get(index-1).position ){  
                doShift();  
            }  
        }else if( index > 0 && index < list.size()-2){  
            if( this.position == list.get(index+1).position || this.position == list.get(index-1).position){  
                doShift();  
            }  
        }  
    }  
      
    private void doShift(){  
        this.direction = (this.direction == Direction.Left) ? Direction.Right : Direction.Left;  
    }  

package cn.dfeng.model;
import java.util.ArrayList;
public class Ant {
 public static final int LENGTH = 27;
 private int position;
 Direction direction;
 /*
  * 在木杆上的蚂蚁队列
  */
 ArrayList<Ant> list;
 
 public Ant( int p, Direction dir, ArrayList<Ant> list ){
  this.position = p;
  this.direction = dir;
  this.list = list;
 }
 /**
  * 蚂蚁行走
  */
 public void walk(){
  
  if( direction == Direction.Right ){
   position++;
  }else{
   position--;
  }
  
  //如果大于最大长度获小于0即视为爬出木杆
  if( position >= LENGTH || position <= 0 ){
   list.remove( this );
  }
 }
 
 /**
  * 蚂蚁调头, 行走一秒后查看自己是不是需要调头
  */
 public void shift(){
  int index = list.indexOf( this );
  if( index == 0 && list.size() > 1 ){
   if( this.position == list.get(1).position ){
    doShift();
   }
  }else if( index == list.size()-1 && index > 0 ){
   if( this.position == list.get(index-1).position ){
    doShift();
   }
  }else if( index > 0 && index < list.size()-2){
   if( this.position == list.get(index+1).position || this.position == list.get(index-1).position){
    doShift();
   }
  }
 }
 
 private void doShift(){
  this.direction = (this.direction == Direction.Left) ? Direction.Right : Direction.Left;
 }
}
 
在Controller包内
view plaincopy to clipboardprint?
package cn.dfeng.control;  
 
import java.util.ArrayList;  
 
import cn.dfeng.model.Ant;  
import cn.dfeng.model.Direction;  
 
public class Controller {  
 
    /* 
     * 蚂蚁初始位置 
     */ 
    private int[] positions = { 3, 7, 11, 17, 23 };  
      
    /* 
     *蚂蚁初始方向 
     */ 
    private Direction[] dir;  
      
    private long timer = 0;  
      
    /** 
     * 指定蚂蚁初始方向, 创建控制器 
     * @param dir 
     */ 
    public Controller( Direction[] dir ){  
        this.dir = dir;  
    }  
      
    public long start(){  
        ArrayList<Ant> list = this.init();  
          
        /* 
         * 蚂蚁队列为空即全部爬出 
         */ 
        while( list.size() != 0 ){  
            //爬行  
            for( int i = 0; i < list.size(); i++ ){  
                Ant ant = list.get(i);  
                ant.walk();  
            }  
            //掉头  
            for( int i = 0; i < list.size(); i++ ){  
                Ant ant = list.get(i);  
                ant.shift();  
            }  
              
            timer++;  
        }  
        return timer;  
    }  
      
    /* 
     * 创建初始蚂蚁队列 
     */ 
    private ArrayList<Ant> init(){  
        ArrayList<Ant> list = new ArrayList<Ant>();  
        for( int i = 0; i < positions.length; i++ ){  
            Ant ant = new Ant( positions[i], dir[i], list );  
            list.add( ant );  
        }  
        return list;  
    }  

package cn.dfeng.control;
import java.util.ArrayList;
import cn.dfeng.model.Ant;
import cn.dfeng.model.Direction;
public class Controller {
 /*
  * 蚂蚁初始位置
  */
 private int[] positions = { 3, 7, 11, 17, 23 };
 
 /*
  *蚂蚁初始方向
  */
 private Direction[] dir;
 
    private long timer = 0;
   
    /**
     * 指定蚂蚁初始方向, 创建控制器
     * @param dir
     */
    public Controller( Direction[] dir ){
     this.dir = dir;
    }
   
    public long start(){
     ArrayList<Ant> list = this.init();
     
     /*
      * 蚂蚁队列为空即全部爬出
      */
     while( list.size() != 0 ){
      //爬行
      for( int i = 0; i < list.size(); i++ ){
       Ant ant = list.get(i);
       ant.walk();
      }
      //掉头
      for( int i = 0; i < list.size(); i++ ){
       Ant ant = list.get(i);
       ant.shift();
      }
      
      timer++;
     }
     return timer;
    }
   
    /*
     * 创建初始蚂蚁队列
     */
    private ArrayList<Ant> init(){
     ArrayList<Ant> list = new ArrayList<Ant>();
     for( int i = 0; i < positions.length; i++ ){
      Ant ant = new Ant( positions[i], dir[i], list );
      list.add( ant );
     }
     return list;
    }
}
 
在Root包内
view plaincopy to clipboardprint?
package cn.dfeng;  
 
import cn.dfeng.control.Controller;  
import cn.dfeng.model.Direction;  
 
public class Simulator {  
 
    private long longest = 0;  
    private long shortest = Long.MAX_VALUE;  
 
    /** 
     * 开始模拟 
     */ 
    public void simulate() {  
        for (int i = 0; i < 32; i++) {  
            Controller con = new Controller(this.getDirections(i));  
            long time = con.start();  
            if( time > longest ){  
                longest = time;  
            }  
            if( time < shortest ){  
                shortest = time;  
            }  
            System.out.println( " Time: " + time );  
        }  
    }  
 
    /* 
     * 创建蚂蚁初始位置 
     */ 
    private Direction[] getDirections(int i) {  
        Direction[] dirs = new Direction[5];  
        String binString = Integer.toBinaryString(i);  
        StringBuilder sb = new StringBuilder();  
        int lack = 5 - binString.length();  
          
        for( int c = 0; c < lack; c++ ){  
            sb.append('0');  
        }  
        sb.append( binString );  
        binString = sb.toString();  
        int p = 0;  
        while( p < binString.length() ) {  
              
            if (binString.charAt(p) == '0') {  
                dirs[p] = Direction.Left;  
            } else {  
                dirs[p] = Direction.Right;  
            }  
            p++;  
        }  
          
        System.out.print( "Round: " + binString );  
 
        return dirs;  
    }  
 
    /** 
     * 打印结果 
     */ 
    public void getResult() {  
        System.out.printf("Longest time %d.\nShortest Time: %d", longest,  
                shortest);  
    }  
 
    public static void main( String[] args ){  
        Simulator sim = new Simulator();  
          
        sim.simulate();  
          
        sim.getResult();  
    }  

package cn.dfeng;
import cn.dfeng.control.Controller;
import cn.dfeng.model.Direction;
public class Simulator {
 private long longest = 0;
 private long shortest = Long.MAX_VALUE;
 /**
  * 开始模拟
  */
 public void simulate() {
  for (int i = 0; i < 32; i++) {
   Controller con = new Controller(this.getDirections(i));
   long time = con.start();
   if( time > longest ){
    longest = time;
   }
   if( time < shortest ){
    shortest = time;
   }
   System.out.println( " Time: " + time );
  }
 }
 /*
  * 创建蚂蚁初始位置
  */
 private Direction[] getDirections(int i) {
  Direction[] dirs = new Direction[5];
  String binString = Integer.toBinaryString(i);
  StringBuilder sb = new StringBuilder();
  int lack = 5 - binString.length();
  
  for( int c = 0; c < lack; c++ ){
   sb.append('0');
  }
  sb.append( binString );
  binString = sb.toString();
  int p = 0;
  while( p < binString.length() ) {
   
   if (binString.charAt(p) == '0') {
    dirs[p] = Direction.Left;
   } else {
    dirs[p] = Direction.Right;
   }
   p++;
  }
  
  System.out.print( "Round: " + binString );
  return dirs;
 }
 /**
  * 打印结果
  */
 public void getResult() {
  System.out.printf("Longest time %d.\nShortest Time: %d", longest,
    shortest);
 }
 public static void main( String[] args ){
  Simulator sim = new Simulator();
  
  sim.simulate();
  
  sim.getResult();
 }
}
 
3. 评析
蚂蚁的初始方向不是向左就是向右, 可以用二进制表示. 5只蚂蚁, 2^5=32个组合.
所以, 用0-31的二进制刚好可以表示蚂蚁的初始方向. 使用: Integer.toBinaryString(i), 不够五位的话左填充0至五位, 即可得到的如01010这样的二进制串, 比如0表示向左, 1表示向右, 即可得到蚂蚁的初始方向.
有了初始方向和初始位置, 就可以使用Controller模拟并比较了.
本文作者:网友 来源: http://blog.csdn.net/Radic_Feng/archive/2010/01/13/5187176.aspx
CIO之家 www.ciozj.com 微信公众号:imciow
    >>频道首页  >>网站首页   纠错  >>投诉
版权声明:CIO之家尊重行业规范,每篇文章都注明有明确的作者和来源;CIO之家的原创文章,请转载时务必注明文章作者和来源;
延伸阅读