posts - 82, comments - 269, trackbacks - 0, articles - 1
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          百度面試題目的答案[原創]

          Posted on 2006-11-10 16:46 itspy 閱讀(11883) 評論(52)  編輯  收藏 所屬分類: 小巧實例JAVA技術

          最近有同學找工作,經常在班級群里發一些大公司的面試,筆試題目.昨天收到這樣一個題目,據說是百度的面試題目.

          ?有一根27厘米的細木桿,在第3厘米、7厘米、11厘米、17厘米、23厘米這五個位置上各有一只螞蟻。 木桿很細,不能同時通過一只螞蟻。開始 時,螞蟻的頭朝左還是朝右是任意的,它們只會朝前走或調頭, 但不會后退。當任意兩只螞蟻碰頭時,兩只螞蟻會同時調頭朝反方向走。假設螞蟻們每秒鐘可以走一厘米的距離。 編寫程序,求所有螞蟻都離開木桿 的最小時間和最大時間。

          看了這個題目之后,突然很感興趣,今天搞了半天把它做出來了,大概花了1個半小時.大公司的題目真是考人.反正都已經用算法實現了,我就不多說了,大家看代碼吧.代碼里面注釋我也盡量全寫了.一共有兩個類,一個是Ant的模型,一個是控制類.原代碼,大家可以在這取得:

          http://www.aygfsteel.com/Files/itspy/baidu.rar



          //////////////////////////////////////
          /*百度面試題
          ?* 有一根27厘米的細木桿,在第3厘米、7厘米、11厘米、17厘米、23厘米這五個位置上各有一只螞蟻。
          ?* 木桿很細,不能同時通過一只螞蟻。開始 時,螞蟻的頭朝左還是朝右是任意的,它們只會朝前走或調頭,
          ?* 但不會后退。當任意兩只螞蟻碰頭時,兩只螞蟻會同時調頭朝反方向走。假設螞蟻們每秒鐘可以走一厘米的距離。
          ?* 編寫程序,求所有螞蟻都離開木桿 的最小時間和最大時間。
          ?*
          ?*
          ?* 分析:題目中的螞蟻只可能相遇在整數點,不可以相遇在其它點,比如3.5cm處之類的,也就是可以讓每只螞蟻走 1秒,然后
          ?* 查看是否有相遇的即可.
          ?*
          ?* 這樣我的程序實現思路就是,初始化5只螞蟻,讓每只螞蟻走1秒,然后看是否有相遇的,如果有則做相應處理.當每只螞蟻都
          ?* 走出木桿時,我就記錄當前時間.這樣就可以得到當前狀態情況下,需要多久可以走出木桿,然后遍歷所有狀態則可以得到所胡
          ?* 可能.
          ?*/

          package baidu;

          public class Ant {
          ?/*
          ? * step 表示螞蟻每一個單位時間所走的長度
          ? */
          ?private final static int step = 1;

          ?/*
          ? * position表示螞蟻所處的初始位置
          ? */
          ?private int position;

          ?/*
          ? * direction表示螞蟻的前進方向,如果為1表示向27厘米的方向走, 如果為-1,則表示往0的方向走。
          ? */
          ?private int direction = 1;

          ?/*
          ? * 此函數運行一次,表示螞蟻前進一個單位時間,如果已經走下木桿則會拋出異常
          ? */
          ?public void walk() {
          ??if (isOut()) {
          ???throw new RuntimeException("the ant is out");
          ??}
          ??position = position + this.direction * step;
          ?};


          ?/**
          ? * 檢查螞蟻是否已經走出木桿,如果走出返回true
          ? *
          ? */

          ?public boolean isOut() {
          ??return position <= 0 || position >= 27;
          ?}

          ?/**
          ? * 檢查此螞蟻是否已經遇到另外一只螞蟻
          ? * @param ant
          ? * @return 如果遇到返回true
          ? */
          ?public boolean isEncounter(Ant ant) {
          ??return ant.position == this.position;
          ?}

          ?/**
          ? * 改變螞蟻的前進方向
          ? */
          ?public void changeDistation() {
          ??direction = -1 * direction;
          ?}


          ?/**
          ? * 構造函數,設置螞蟻的初始前進方向,和初始位置
          ? * @param position
          ? * @param direction
          ? */
          ?public Ant(int position, int direction) {
          ??this.position = position;
          ??if (direction != 1) {
          ???this.direction = -1;//方向設置初始位置,比如為0時,也將其設置為1.這樣可以方便后面的處理
          ??} else {
          ???this.direction = 1;
          ??}
          ?}

          }

          ?

          /////////////////////////////////////////////////////////


          package baidu;

          public class Controller {

          ?public static void main(String[] args) {

          ??int time = 0;
          ??for (int i = 0; i < 32; i++) {
          ???Ant[] antArray = getAntList(getPoistions(), getDirections(i));
          ???while (!isAllOut(antArray)) {
          ????for (Ant ant : antArray) {
          ?????if (!ant.isOut()) {
          ??????ant.walk();
          ?????}
          ????}
          ????time++;
          ????// 查看是否有已經相遇的Ant,如果有則更改其前進方向
          ????dealEncounter(antArray);
          ???}
          ???System.out.println(time);

          ???// 將時間歸0,這樣可以重新設置條件,再次得到全部走完所需要的時間.
          ???time = 0;
          ??}

          ?}

          ?/**
          ? * 這個函數的算法很亂,但暫時能解決問題
          ? *
          ? * @param list
          ? */
          ?public static void dealEncounter(Ant[] antArray) {

          ??int num_ant = antArray.length;
          ??for (int j = 0; j < num_ant; j++) {
          ???for (int k = j + 1; k < num_ant; k++) {
          ????if (antArray[j].isEncounter(antArray[k])) {
          ?????antArray[j].changeDistation();
          ?????antArray[k].changeDistation();
          ????}
          ???}
          ??}

          ?}

          ?/**
          ? * 因為有5只Ant,所以組合之后有32種組合.剛好用5位二進制來表示,如果為0則表示Ant往0的方向走 如果為1,則表示往27的方向走
          ? *
          ? * 注:在通過Ant的構造函數設置初始值時,通過過濾把0修改成了-1.
          ? */
          ?public static int[] getDirections(int seed) {
          ??int result[] = new int[5];
          ??result[0] = seed % 2;
          ??result[1] = seed / 2 % 2;
          ??result[2] = seed / 4 % 2;
          ??result[3] = seed / 8 % 2;
          ??result[4] = seed / 16 % 2;

          ??System.out.println("directions is " + result[0] + "|" + result[1] + "|"
          ????+ result[2] + "|" + result[3] + "|" + result[4]);

          ??return result;

          ?}

          ?/**
          ? * 批量設置Ant的初始位置,這樣設置不是十分必要,可以直接在代碼中設置
          ? *
          ? * @return
          ? */
          ?public static int[] getPoistions() {
          ??return new int[] { 3, 7, 11, 17, 23 };
          ?}

          ?/**
          ? * 取得設置好初始值的5只Ant
          ? *
          ? * @param positions
          ? * @param directions
          ? * @return
          ? */
          ?public static Ant[] getAntList(int[] positions, int[] directions) {
          ??Ant ant3 = new Ant(positions[0], directions[0]);
          ??Ant ant7 = new Ant(positions[1], directions[1]);
          ??Ant ant11 = new Ant(positions[2], directions[2]);
          ??Ant ant17 = new Ant(positions[3], directions[3]);
          ??Ant ant23 = new Ant(positions[4], directions[4]);

          ??return new Ant[] { ant3, ant7, ant11, ant17, ant23 };
          ?}

          ?/**
          ? * 判斷是否所有的Ant都已經走出了木桿,也就是設置退出條件
          ? *
          ? * @param antArray
          ? * @return
          ? */
          ?public static boolean isAllOut(Ant[] antArray) {
          ??for (Ant ant : antArray) {
          ???if (ant.isOut() == false) {
          ????return false;
          ???}
          ??}
          ??return true;
          ?}
          }

          ?


          評論

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-11 00:27 by 差沙
          dealEncounter這里。
          不相鄰的螞蟻是不會相遇的。

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-11 11:44 by itspy
          是的,這個dealEncounter有很大改進的空間.不過你剛才說的這個我之前沒有考慮到.

          我之前只是考慮到了:有一些螞蟻已經走出了木桿,就不用去處理了.不過實現起來有些不太方便.就沒有去處理了.

          所以在注釋中,我也說明了這個dealEncounter肯定可以進行.


          謝謝你的評論

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-11 15:29 by itspy
          改進后的dealEncounter為,謝謝差沙的回復


          /**
          * 這個函數的算法很亂,但暫時能解決問題
          *
          * @param list
          */
          public static void dealEncounter(Ant[] antArray) {

          int num_ant = antArray.length;
          for (int j = 0; j < num_ant-1; j++) {
          if (antArray[j].isEncounter(antArray[j + 1])) {
          antArray[j].changeDistation();
          antArray[j + 1].changeDistation();

          }
          }

          }

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-12 11:13 by 路過
          /*百度面試題
          * 有一根27厘米的細木桿,在第3厘米、7厘米、11厘米、17厘米、23厘米這五個位置上各有一只螞蟻。
          * 木桿很細,不能同時通過一只螞蟻。開始 時,螞蟻的頭朝左還是朝右是任意的,它們只會朝前走或調頭,
          * 但不會后退。當任意兩只螞蟻碰頭時,兩只螞蟻會同時調頭朝反方向走。假設螞蟻們每秒鐘可以走一厘米的距離。
          * 編寫程序,求所有螞蟻都離開木桿 的最小時間和最大時間。
          *
          */
          public class TestMain {
          /**
          * @param args
          */
          public static void main(String[] args) {
          AntSubjectCalculate calculate=new AntSubjectCalculate(27,1000);
          Ant ant1=new Ant(calculate,1,true,3,null);
          ant1.setName("a");
          Ant ant2=new Ant(calculate,1,true,7,ant1);
          ant2.setName("b");
          Ant ant3=new Ant(calculate,1,false,11,ant2);
          ant3.setName("c");
          Ant ant4=new Ant(calculate,1,false,17,ant3);
          ant4.setName("d");
          Ant ant5=new Ant(calculate,1,false,23,ant4);
          ant5.setName("e");
          calculate.notifyAllObjects();//開始運行
          System.out.println("總共用時:"+calculate.sumTime());
          }

          }

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-12 11:14 by 路過
          public class Ant implements Subject,Runnable {
          private long position;//位置
          private String name;//名字
          private int rate;//速度
          private int useTime;//走完全程用時
          private boolean isStop;//停止,說明是否已經走出木桿,是則true,否則false
          private boolean forWord;//螞蟻的前進方向false為負,true為正
          //private int distance;//每次的間隔的路程
          private List observers =new ArrayList();
          private Ant frontAnt;//前一個螞蟻
          public void run() {
          try{
          notifyObservers();
          }catch(Exception e){
          e.printStackTrace();
          }
          }
          /*public int getDistance(){
          return this.distance;
          }
          public void setDistance(int increment){
          this.useTime+=increment;
          this.distance=this.rate*increment;
          }*/
          public void seIsStop(boolean isStop){
          this.isStop=isStop;
          }
          public boolean isStop(){
          return this.isStop;
          }

          public void setUseTime(int useTime){
          this.useTime=useTime;
          }
          public int getUseTime(){
          return this.useTime;
          }
          public void setFrontAnt(Ant frontAnt){
          this.frontAnt=frontAnt;
          }
          public Ant getFrontAnt(){
          return this.frontAnt;
          }
          public Ant(EveryCalculate concreteCalculate,int rate,boolean forWord,long position,Ant frontAnt){
          this.rate=rate;
          this.position=position;
          this.forWord=forWord;
          this.isStop=false;
          setFrontAnt(frontAnt);
          concreteCalculate.add(this);
          attach((Observer)concreteCalculate);
          }
          public void attach(Observer observer) {
          observers.add(observer);
          }

          public void detach(Observer observer) {
          observers.remove(observer);
          }

          public void notifyObservers()throws Exception{
          for(Iterator it=observers.iterator();it.hasNext();){
          Observer observer=(Observer)it.next();
          observer.update(this);
          }
          }

          public boolean isForWord() {
          return forWord;
          }
          public void setForWord(boolean forWord) {
          this.forWord = forWord;
          }
          public String getName() {
          return name;
          }
          public void setName(String name) {
          this.name = name;
          }
          public long getPosition() {
          return position;
          }
          //改變螞蟻的前進方向,當和前一個螞蟻相遇時就兩只螞蟻都調頭
          public void setPosition(long position) {
          this.position = position;
          }
          public int getRate() {
          return rate;
          }
          public void setRate(int rate) {
          this.rate = rate;
          }
          public void inverse(){
          this.forWord=!this.forWord;
          }
          }

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-12 11:14 by 路過
          public interface Observer {
          public void update(Subject object)throws Exception;
          }

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-12 11:15 by 路過
          /*
          * 抽像層,提供了要加入計算的對象集合,繼承的子類要實現他們自已的運算規則
          */
          public abstract class EveryCalculate {
          protected List calculates=new ArrayList();//每個要計算的對象
          public abstract void calculate(Object object)throws Exception;//每種算法
          public void add(Object object){
          calculates.add(object);
          }
          public void remove(Object object){
          calculates.remove(object);
          }
          public Iterator iterator(){
          return calculates.iterator();
          }
          public int size(){
          return calculates.size();
          }
          public abstract void notifyAllObjects ();
          }

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-12 11:15 by 路過
          public interface Subject {
          public void attach(Observer observer);
          public void detach(Observer observer);
          public void notifyObservers()throws Exception;
          }

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-12 11:16 by 路過
          /*
          * 實現運算規則
          */
          public class AntSubjectCalculate extends EveryCalculate implements Observer {
          private final int length;
          private final long incrementTime;//表示螞蟻前進一個單位時間,間隔時間以毫秒計算
          private int useTime;
          public AntSubjectCalculate(int length,long incrementTime){
          this.length=length;
          this.incrementTime=incrementTime;
          }
          public void calculate(Object object)throws Exception{
          Ant ant=(Ant)object;//在算法中確定他的前后節點
          int second=(int)this.getSecond(this.incrementTime);//每秒
          ant.setUseTime(ant.getUseTime()+second);
          if(ant.isForWord())
          ant.setPosition(ant.getRate()* second+ant.getPosition());
          else
          ant.setPosition(ant.getPosition()-ant.getRate()*second);
          Ant frontAnt = ant.getFrontAnt();
          //當兩個螞蟻走到同一點時就轉向
          if(frontAnt!=null && frontAnt.getPosition()>= ant.getPosition()){
          System.out.println("螞蟻:"+ant.getName()+"和"+frontAnt.getName()+"轉向了!");
          ant.inverse();
          frontAnt.inverse();
          }
          if(ant.getPosition() >= this.getLength() || ant.getPosition() <= 0){
          ant.seIsStop(true);//停止這個螞蟻的行動!
          if(ant.getUseTime()>this.useTime){
          this.useTime = ant.getUseTime();//保存最后一只螞蟻的時間
          }
          System.out.println("螞蟻:"+ant.getName()+"已出木桿,用時:" + ant.getUseTime());
          }
          System.out.println("螞蟻:"+ant.getName()+"位置"+ant.getPosition());
          }
          //這個方法也可移出去,作為一個外層的控制觸了器來用,主要模擬螞蟻開始行走的情況
          public void notifyAllObjects (){
          while(this.size()>0){
          for(Iterator it=this.iterator();it.hasNext();){
          Ant ant=(Ant)it.next();
          ant.run();
          if(ant.isStop()){
          it.remove();
          }
          }
          }
          }
          public void update(Subject object)throws Exception{
          calculate(object);
          }
          public int getLength(){
          return this.length;
          }
          public long sumTime(){
          return useTime;
          }
          public long getIncrementTime(){
          return this.incrementTime;
          }
          //算成秒
          public long getSecond(long time){
          return time/1000;
          }
          }

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-12 11:21 by 路過
          我是用觀察者模式實現的。實現之前,沒有看原創的實現,只按自已的想法寫了這段代碼!不是為了比較誰好誰壞,只不過想了表一下自已的一些見解,因為代碼是相通的,只是實現手法不一相而已。歡迎相互交流,我的郵箱是yoohoo.lai@163.com

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-12 11:24 by 路過
          外面代碼入口在public class TestMain 之中,由于沒加更多注釋.可能看起來有點費力

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-12 15:49 by itspy
          @路過
          之前我也想過用觀察者模式來實現,但是在最后寫出了Ant的模式之后,發現不用這個模式也很容易實現,也就沒有用這個模式了.

          謝謝討論

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-12 18:56 by 路過
          其實代碼的實現,是有多種方法的,但如果百度的題目改一下可能要用N只螞蟻,用不同的速度離開時,這時侯,就可能要改算法,而我實現這個的目的就在于,如果提出了這個要求我只要,另寫一個實現算法就能實現另外的題目public class *Calculate extends EveryCalculate implements Observer
          而不用更改其它代碼!這也是我為什么會考慮用觀察者實現的原因了!

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-12 19:08 by 路過
          不相鄰的螞蟻,我的做法是直接在Ant類中用鏈表結構定義的。其實細仔想起來這個這一層應該跟業務對象隔離開來!螞蟻的排列規則,應該在寫一個接口和實現類去定義,這樣當改變排列順序的時侯也只要多寫一個實現類而已!

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-12 21:11 by itspy
          你說的很對,其實之前我也考慮過這個問題,百度剛好把Ant放置在了幾個特別的位置.這時幾個Ant只可能在整數點相遇.比如要是有一個Ant在5處,有一個在8處.這時我們實現時,可能就不能一厘米一厘米的走了.


          不錯,你的實現確實比我要好多了.

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-13 16:30 by xinheqishi
          樓上的兄弟們,你們是不是把問題復雜化了??

          如果五個螞蟻最初的狀態已經確定,那么全部離開木桿的時間已經確定。所以問題的關鍵是如何決定螞蟻最初的狀態。

          1.把木桿根據中點分為左半部分和右半部分。
          2.作為一只螞蟻,要想最快地離開木桿,首先是判斷自己屬于木桿的哪部分。如果是左,則向左走;如果是右,就向右走。這樣就可最快地離開木桿。
          3.如果是想最慢地離開木桿,只需改成相反規則就可:如果是左,則向右走;如果是右,就向左走。這個有點意思,可能有人懷疑,真的是這樣嗎?

          問題就是這么簡單,呵呵。


          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-13 17:16 by itspy
          @xinheqishi

          樓上說的第3點,在這個場景中是對的,但不知道如何去證明他的通用性.如第3點不成立的話,則只好使用遍歷去找出所有的時間了.

          通過遍歷查找,有32種可能的方向組合,但有16種"并列"為最慢.
          當然,最快的只有一種,就是你說的那種


          哪個能想辦法證明一下這一點嗎?
          3.如果是想最慢地離開木桿,只需改成相反規則就可:如果是左,則向右走;如果是右,就向左走。這個有點意思,可能有人懷疑,真的是這樣嗎?

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-13 19:31 by joycsharp
          通過算各個螞蟻運動的路程可以算出每個螞蟻的運動時間

          主要控制部分:
          int[] pos ={ 3, 7, 11, 17, 23 }; //位置
          ArrayList antlist = new ArrayList(); //存放運行中螞蟻
          Random ran = new Random();
          foreach (int p in pos)
          {
          int speed = ran.Next(11) % 2 == 0 ? 1 : -1; //隨機方向,1 or -1
          Console.WriteLine(p.ToString() + ":" + speed.ToString());
          antlist.Add(new Ant(p,speed));
          }
          while (antlist.Count > 0)
          {
          ArrayList delete = new ArrayList(); //以出桿的螞蟻
          foreach (Ant a in antlist)
          {
          a.movenext();
          if (a.isout) //出桿
          {
          delete.Add(a);
          }
          }
          foreach(Ant a in delete) //在antlist刪除已出桿的螞蟻
          {
          antlist.Remove(a);
          }
          delete.Clear();
          for (int i = 0; i < antlist.Count; i++) //判斷此時是否有相遇的,如有,各自掉頭
          {
          for (int j = i; j < antlist.Count; j++)
          {
          Ant a = (Ant)antlist[i];
          Ant b = (Ant)antlist[j];
          if (a.pos == b.pos)
          {
          if (a.speed + b.speed == 0)
          {
          a.speed = -a.speed;
          b.speed = -b.speed;
          }
          }
          }
          }
          }


          //ant類



          public class Ant
          {
          public int pos; //初始位置
          public int speed; //速度
          public bool isout = false;
          int totaldistance = 0; //運動總距離
          public Ant(int pos,int speed)
          {
          this.pos = pos;
          this.speed = speed;
          }
          public void movenext()
          {
          if (pos <= 0 || pos >= 27) //判斷是否出桿
          {
          isout = true;
          Console.WriteLine("out:" + this.totaldistance.ToString());
          }
          else
          {
          totaldistance += Math.Abs(speed);
          pos += speed;
          }
          }
          }


          大致算了下,好象沒錯誤。c#編寫

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-13 19:39 by joycsharp
          覺得此題比較有迷惑性,螞蟻碰頭后各自掉頭,實際整個過程中螞蟻都在運動,如果能算出螞蟻走的總路程,那么螞蟻的運動時間也就能得出。覺得這樣算法會簡單許多

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-14 08:55 by 路過
          樓上說的觀點和我的初衷的出發點是不一樣的,如果就是了解決這個問題其實方法可以很簡單,這個題目不就為了算出五只螞蟻離開一個桿子嗎?其實只要抓住一點就行,就是比較最后一只離開桿子的螞蟻走的總的路程就可以了。路程最短的也就最快,路程最大的就最慢!應用數學上一些算法就能解決。這根本用不著一個一個按間隔時間遍歷,耗這個性能在里面。
          之所以用模式的東西去解決問題,其實是把這道題模擬了一下螞蟻的行走的場景。注重的是他的擴展性,而不是算法本身!

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-14 09:04 by 路過
          所以從算法的角度來講這個是把簡單的東西復雜化,這是沒必要的!從軟件的開閉原則來講,這些也不算什么!

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-14 09:33 by xinheqishi
          哪個能想辦法證明一下這一點嗎?
          3.如果是想最慢地離開木桿,只需改成相反規則就可:如果是左,則向右走;如果是右,就向左走。這個有點意思,可能有人懷疑,真的是這樣嗎?

          ×××××××××××××××××××××××××××××××××××××××××
          樓主你好,我是憑著對數學的一種直覺得出這個結論的。并沒有經過嚴格的證明,忽悠了一下樓主,呵呵。見笑見笑!

          當時我是這么想的,把左邊的所有螞蟻作為一個整體,右邊的作為一個整體,哪么這個情形就跟木桿上只有兩只螞蟻的情形就一樣了。這是從純數學的角度去思考。

          我覺得從解決問題的角度,應該是這種思路,直奔主題。簡單的問題就盡量用簡單的方法解決。

          Java編程方面,我只是一個初學者,我還得謝謝樓主,讓我又多學了點。

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-14 09:37 by xinheqishi
          之所以用模式的東西去解決問題,其實是把這道題模擬了一下螞蟻的行走的場景。注重的是他的擴展性,而不是算法本身!

          ×××××××××××××××××××××××××××××××××××××××××
          從學東西的角度,我是認可這個觀點的。

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-14 10:17 by xinheqishi
          模擬了一下螞蟻的行走的場景。

          關于這點,我當時還有這么一個想法:設計兩個類,一個是螞蟻,一個是木桿。
          木桿用來記錄狀態,如某點上的值為0表示該點上沒有螞蟻,為1表示有一個螞蟻,為2表示有兩個螞蟻(即碰撞)。螞蟻從A走到B,A上的值減1,B上的值加1。木桿上只要發生有X點值為2的情況,馬上就讓X點的兩個螞蟻調頭。

          問下大家這個思路是否可行?

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-14 10:20 by joycsharp
          整理成模式應該不是件難事把,既然是面視的題目,就要簡單快速的解決問題,這才是重要

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-14 10:57 by xinheqishi
          樓上的兄弟,實話說,Java方面我只是個新手,設計模式也還沒怎么接觸,不過挺有興趣的。還請兄弟多指教。你的代碼我看了,感覺我的思路跟你的觀察者模式是類似的。木桿就相當于是個觀察者了吧?

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-17 10:35 by thinker[匿名]
          樓上說的第3點,在這個場景中是對的,但不知道如何去證明他的通用性.如第3點不成立的話,則只好使用遍歷去找出所有的時間了.

          通過遍歷查找,有32種可能的方向組合,但有16種"并列"為最慢.
          當然,最快的只有一種,就是你說的那種

          ============
          最快的擺放

          1.把木桿根據中點分為左半部分和右半部分。
          2.作為一只螞蟻,要想最快地離開木桿,首先是判斷自己屬于木桿的哪部分。如果是左,則向左走;如果是右,就向右走。這樣就可最快地離開木桿。

          最慢的擺放
          1, 除非在中點,每只螞蟻離開木桿都有一個近端距離, 遠端距離
          2, 只要保證5只螞蟻中 遠端距離最長的螞蟻面向遠端, 其他的螞蟻隨便擺放即可。 所以在"32種可能的方向組合,有16種并列為最慢".

          程序懶得寫了 最多10行解決問題

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-17 14:32 by itspy
          回復樓上:
          我想這個題目讓人來做,肯定比電腦快.所以樓上才能這么游刃有余的這樣分析,找出答案 .

          1)你如何讓程序找出:5只螞蟻中哪個的遠端距離最長?
          2)遠端距離如何定義?要知道每只螞蟻的方向的改變最終可能都會影響到其它的螞蟻的爬行距離.遠端距離可能并不好算.

          這兩個問題我不大會解決,更不用說10行代碼了,這個請樓幫忙說清楚些,或者是其它有人明白的,講講也行.

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-20 10:57 by thinker[匿名]
          以題目為例
          "有一根27厘米的細木桿,在第3厘米、7厘米、11厘米、17厘米、23厘米這五個位置上各有一只螞蟻"

          3cm 的 (近端3,遠端24)
          7 (7,20)
          11 (11,16)
          17 (10,17)
          23 (4,23)

          所以只要保證3 厘米的螞蟻面向24的一端 其他的螞蟻隨便擺

          把碰撞簡化成AB相遇延a,b原方向繼續前進,即可求出最大時間 就是最大的遠端距離/速度。

          詞解法可以用于任意位置 任意速度, 但必須保證每個螞蟻速度相同

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-20 11:13 by itspy
          樓上的解法十分簡單明白,不過我還是有些不解^_^。


          于是想找個反例,但找了半天,也沒找到。


          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-20 14:58 by thinker[匿名]
          沒有反例的啦, 哪怕有10000只螞蟻在上面, 只要保證最遠端的螞蟻面向遠端, 最長的時間就是最遠端/速度。

          這道題最大的迷惑項 是相撞, 如果轉換成只是相遇,擦肩而過就好理解了,并且這種轉化不影響結果。

          假設A B相向而行,A距遠端的距離為a, B為b, A B各自走了距離c以后相遇,碰撞,反向, A要走(b-c)距離, B要走(a-c), 總共A走了b, B走了a距離。所以max(a,b)就是最遠距離,相撞還是擦肩而過只是影響到是A走了a還是走了b, 對整體答案沒有影響。

          應該可以有更縝密的數學推理,我的數學很差,就不獻丑了。

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-11-20 15:34 by itspy
          這道題最大的迷惑項 是相撞, 如果轉換成只是相遇,擦肩而過就好理解了。


          可能大部分看過這個帖子的人都被這個迷惑。反正我是被迷惑了。

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-12-06 14:55 by hyry
          呵呵,這個題目有意思,看上去復雜,其實簡單。我的理解是如果螞蟻轉身不需要時間,而且所有的螞蟻都長得一樣,而且我眼神也不好的話,那么兩只螞蟻是碰撞還是擦肩而過,看上去都一樣,反正我看到的先是兩個黑點靠近,然后這兩個黑點碰到一起,然后又分開。

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2006-12-06 16:30 by xinheqishi
          哈,回來看看,看見樓上,^_^,高!

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2007-01-18 20:19 by ahuan
          好多聰明人,thinker果然是個思考者.

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2007-02-12 15:51 by Signture.updata(土豆)
          高! thinker 是個高人啊,能夠看到本質問題。

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2007-03-30 09:41 by 大河
          高!!!

          這才叫解決問題呢。。。
          編碼編了變天,都看不懂,屁用!!!

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2007-06-27 12:33 by suntao19830709@gmail.com
          /**
          * Copyright 1994-2006. EMC Corporation. All Rights Reserved.
          */
          package ant;

          /**
          *
          * @version ${version}, Jun 27, 2007 11:23:46 AM
          * @author Tao Sun (Sun_Tao@emc.com)
          * @since JDK1.5
          */
          public class Ant
          {
          public int direction = 1;
          public int distance = 0;
          public int maxDistance = 1;

          public Ant(int distance, int direction, int maxDistance)
          {
          this.direction = direction;
          this.distance = distance;
          this.maxDistance = maxDistance;
          }

          public int getDistance()
          {
          return distance;
          }

          public void move()
          {
          if(!isOut())
          {
          distance += direction;
          }
          }

          private void changeDirection()
          {
          direction = direction == 1? -1 : 1;
          }

          public void check(int distance1, int distance2, int distance3, int distance4)
          {
          if(distance == distance1||distance == distance2||distance == distance3||distance == distance4)
          {
          changeDirection();
          }
          }

          public boolean isOut()
          {
          return distance == 0 || distance == maxDistance;
          }
          }


          /**
          * Copyright 1994-2006. EMC Corporation. All Rights Reserved.
          */
          package ant;

          /**
          * @version ${version}, Jun 27, 2007 11:37:34 AM
          * @author Tao Sun (Sun_Tao@emc.com)
          * @since JDK1.5
          */
          public class Run
          {
          public static void main(String[] args)
          {
          for(int i = 0; i<32; i++)
          {
          String str = Integer.toBinaryString(i);
          str = formatString(str);
          Ant ant1 = new Ant(3, getDirection(str, 0), 27);
          Ant ant2 = new Ant(7, getDirection(str, 1), 27);
          Ant ant3 = new Ant(11, getDirection(str, 2), 27);
          Ant ant4 = new Ant(17, getDirection(str, 3), 27);
          Ant ant5 = new Ant(23, getDirection(str, 4), 27);
          run(ant1, ant2, ant3, ant4, ant5);
          }
          }

          private static void run(Ant ant1, Ant ant2,Ant ant3, Ant ant4, Ant ant5)
          {
          int i = 0;
          while (!(ant1.isOut()&&ant2.isOut()&&ant3.isOut()&&ant4.isOut()&&ant5.isOut()))
          {
          ant1.move();
          ant2.move();
          ant3.move();
          ant4.move();
          ant5.move();
          checkAnt(ant1, ant2,ant3, ant4,ant5);
          i++;
          }
          System.out.println(i);
          }

          private static void checkAnt(Ant ant1, Ant ant2,Ant ant3, Ant ant4, Ant ant5)
          {
          int distance1 = ant1.getDistance();
          int distance2 = ant2.getDistance();
          int distance3 = ant3.getDistance();
          int distance4 = ant4.getDistance();
          int distance5 = ant5.getDistance();
          ant1.check(distance2, distance3, distance4, distance5);
          ant2.check(distance1, distance3, distance4, distance5);
          ant3.check(distance1, distance2, distance4, distance5);
          ant4.check(distance1, distance2, distance3, distance5);
          ant5.check(distance1, distance2, distance3, distance4);
          }


          private static int getDirection(String str, int i)
          {
          if(str.charAt(i)=='0')
          {
          return -1;
          }
          else
          {
          return 1;
          }
          }

          private static String formatString(String str)
          {
          int length = str.length();
          for(int i = 0; i< 5 - length ; i++)
          {
          str = "0" + str;
          }
          return str;
          }
          }

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2007-06-27 12:40 by suntao19830709@gmail.com
          俺上面的代碼沒寫注釋,但相信有一定編程經驗的很容易看懂.關鍵的一個地方就是5個螞蟻的方向就是2的5次方種可能,故用0-31的2進制數的對應位是1還是0來表示方向.

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2007-06-27 13:07 by suntao19830709@gmail.com
          其實編程歸編程,其實還有個更深刻的原理.就是樓上各位已經分析過的.
          1:微觀上看a螞蟻和b螞蟻相遇后是調頭了.即a現在是沿著b本應該走的路走了,b沿著a本應該走的路繼續走.
          2:宏觀上如果把a螞蟻和b螞蟻看成是完全一樣的螞蟻,那么相當于兩個螞蟻都沒有調頭.
          3:如果一時想不明白,可以想最簡單的情形,就只有兩只螞蟻從棍子兩端相向而行,在中間遇到后調頭,是不是跟沒調頭一樣呢???
          4:這就是有名的鬼魂理論,跟物理上的動量守恒很類似.

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2007-06-27 13:34 by suntao19830709@gmail.com
          數學歸納證明來了...
          1:假設如果不碰頭,有一個螞蟻a0的需要走的距離為S0.時間為t0,所有螞蟻速度為v,則s0=v*t0.同理,還有一個螞蟻a1,需要走的距離為S1,時間為t1, s1= v*t1.
          2:當a0遇到a1的時候,假設走了t秒,a1剩的距離為s0-v*t.因此a1剩的距離為v*t0-v*t,剩下的時間為t0-t,恰好為a0本來走到頭需要的時間.因此此時a1總共需要走出的時間為t0.而a0需要走出的時間總共為t1.
          3:一般來說,當螞蟻aN遇到a(N+1)的時候,aN原本需要的總共的時間tN被賦給了a(N+1),而t(N+1)被賦給了aN.
          4:因此n只螞蟻如果遇到不調頭走出需要的時間分別為t1,t2,....tN,那么每一次有螞蟻碰頭的時候,他們需要的時間仍然為t1,t2,....tN,只是具體哪只螞蟻需要多少時間可能互相有交換.
          5:因此最大最小時間就是最后一只能走出去的螞蟻的最大最小時間.

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2007-07-10 07:24 by zhanghk
          有個問題,如果所有螞蟻的初始狀態都確定了,所有走出去應該只有一個時間,何來最小時間和最大時間?

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2007-08-24 17:15 by 林林
          這道題求最長時間只能用編程來解決。
          Thinker所說的理解看似很對,但有漏洞,我這里只簡單的舉個反例吧。
          還是長度27厘米的樹桿,只有三只螞蟻,3厘米有一只,7厘米有一只,25厘米有一只。3厘米向右,7厘米向左,25厘米向左,最后所花時間為27厘米/速度。
          而如果7厘米和25厘米得螞蟻都向右,那么所花時間為24厘米/速度。
          如果按Thinker所說把3厘米的向右,其他隨便擺,怎么找出這兩個誰大啊,所以還是要遍歷的

          # re: 百度面試題目的答案[原創][未登錄]  回復  更多評論   

          2007-10-12 14:26 by Allen
          @林林
          Thinker的理解沒有錯,是你搞錯了一個地方。Thinker說的是最遠端的螞蟻朝向遠端,因此在你的例子里面,應該是25厘米的螞蟻朝左,而其他的螞蟻隨便擺,這樣才是最大時間。

          # re: 百度面試題目的答案[原創][未登錄]  回復  更多評論   

          2007-10-12 14:29 by Allen
          有個問題,如果所有螞蟻的初始狀態都確定了,所有走出去應該只有一個時間,何來最小時間和最大時間?
          ==============================================

          題目中說了:螞蟻的頭向左向右是隨機的,所以初始狀態不是確定的,這樣就有最小時間和最大時間。

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2007-10-21 15:02 by lovegiven
          toooooooooooooooooooooooooold
          就是一個穿過的問題,不用寫程序,微軟也考過

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2007-10-24 12:40 by cnc224
          貪心,相遇當成路過

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2007-10-25 20:49 by ysuncn
          #include<iostream>
          using namespace std;
          class ant
          {
          public:
          bool orient; //0-left;1-right;
          short pos; //1-27;
          bool onbar; //0-off;1-on;
          void meet()
          {
          orient=orient>0?0:1;
          }
          void move()
          {
          if(orient==0) pos--;
          else pos++;
          if(pos==0||pos==28)onbar=0;
          }
          };
          int main()
          {
          ant a1,a2,a3,a4,a5;
          cout<<"orient(0-left;1-right)"<<endl;
          for(int i1=0;i1<=1;i1++)
          for(int i2=0;i2<=1;i2++)
          for(int i3=0;i3<=1;i3++)
          for(int i4=0;i4<=1;i4++)
          for(int i5=0;i5<=1;i5++)
          {
          a1.orient=i1;a2.orient=i2;a3.orient=i3;a4.orient=i4;a5.orient=i5;
          a1.pos=3;a2.pos=7;a3.pos=11;a4.pos=17;a5.pos=23;
          a1.onbar=1;a2.onbar=1;a3.onbar=1;a4.onbar=1;a5.onbar=1;

          cout<<"orient:"<<a1.orient<<a2.orient<<a3.orient<<a4.orient<<a5.orient<<" ";
          short time=0;
          while(a1.onbar||a2.onbar||a3.onbar||a4.onbar||a5.onbar)
          {
          if(a1.onbar) a1.move();
          if(a2.onbar) a2.move();
          if(a3.onbar) a3.move();
          if(a4.onbar) a4.move();
          if(a5.onbar) a5.move();
          if(a1.pos+1==a2.pos&&a1.onbar&&a2.onbar){a1.meet();a2.meet();}
          if(a2.pos+1==a3.pos&&a2.onbar&&a3.onbar){a2.meet();a3.meet();}
          if(a3.pos+1==a4.pos&&a3.onbar&&a4.onbar){a3.meet();a4.meet();}
          if(a4.pos+1==a5.pos&&a4.onbar&&a5.onbar){a4.meet();a5.meet();}
          time++;
          }
          cout<<"cost time:"<<time<<"s"<<endl;
          }
          }


          orient(0-left;1-right)
          orient:00000 cost time:23s
          orient:00001 cost time:17s
          orient:00010 cost time:23s
          orient:00011 cost time:11s
          orient:00100 cost time:23s
          orient:00101 cost time:17s
          orient:00110 cost time:23s
          orient:00111 cost time:17s
          orient:01000 cost time:23s
          orient:01001 cost time:21s
          orient:01010 cost time:23s
          orient:01011 cost time:21s
          orient:01100 cost time:23s
          orient:01101 cost time:21s
          orient:01110 cost time:23s
          orient:01111 cost time:21s
          orient:10000 cost time:25s
          orient:10001 cost time:25s
          orient:10010 cost time:25s
          orient:10011 cost time:25s
          orient:10100 cost time:25s
          orient:10101 cost time:25s
          orient:10110 cost time:25s
          orient:10111 cost time:25s
          orient:11000 cost time:25s
          orient:11001 cost time:25s
          orient:11010 cost time:25s
          orient:11011 cost time:25s
          orient:11100 cost time:25s
          orient:11101 cost time:25s
          orient:11110 cost time:25s
          orient:11111 cost time:25s

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2007-10-25 21:00 by ysuncn
          @ysuncn小馬虎一下,呵呵bar 0-27

          #include<iostream>
          using namespace std;
          class ant
          {
          public:
          bool orient; //0-left;1-right;
          short pos; //0-27;
          bool onbar; //0-off;1-on;
          void meet()
          {
          orient=orient>0?0:1;
          }
          void move()
          {
          if(orient==0) pos--;
          else pos++;
          if(pos==0||pos==27)onbar=0;
          }
          };
          int main()
          {
          ant a1,a2,a3,a4,a5;
          cout<<"orient(0-left;1-right)"<<endl;
          for(int i1=0;i1<=1;i1++)
          for(int i2=0;i2<=1;i2++)
          for(int i3=0;i3<=1;i3++)
          for(int i4=0;i4<=1;i4++)
          for(int i5=0;i5<=1;i5++)
          {
          a1.orient=i1;a2.orient=i2;a3.orient=i3;a4.orient=i4;a5.orient=i5;
          a1.pos=3;a2.pos=7;a3.pos=11;a4.pos=17;a5.pos=23;
          a1.onbar=1;a2.onbar=1;a3.onbar=1;a4.onbar=1;a5.onbar=1;

          cout<<"orient:"<<a1.orient<<a2.orient<<a3.orient<<a4.orient<<a5.orient<<" ";
          short time=0;
          while(a1.onbar||a2.onbar||a3.onbar||a4.onbar||a5.onbar)
          {
          if(a1.onbar) a1.move();
          if(a2.onbar) a2.move();
          if(a3.onbar) a3.move();
          if(a4.onbar) a4.move();
          if(a5.onbar) a5.move();
          if(a1.pos+1==a2.pos&&a1.onbar&&a2.onbar){a1.meet();a2.meet();}
          if(a2.pos+1==a3.pos&&a2.onbar&&a3.onbar){a2.meet();a3.meet();}
          if(a3.pos+1==a4.pos&&a3.onbar&&a4.onbar){a3.meet();a4.meet();}
          if(a4.pos+1==a5.pos&&a4.onbar&&a5.onbar){a4.meet();a5.meet();}
          time++;
          }
          cout<<"cost time:"<<time<<"s"<<endl;
          }
          }

          orient(0-left;1-right)
          orient:00000 cost time:23s
          orient:00001 cost time:17s
          orient:00010 cost time:23s
          orient:00011 cost time:11s
          orient:00100 cost time:23s
          orient:00101 cost time:17s
          orient:00110 cost time:23s
          orient:00111 cost time:16s
          orient:01000 cost time:23s
          orient:01001 cost time:20s
          orient:01010 cost time:23s
          orient:01011 cost time:20s
          orient:01100 cost time:23s
          orient:01101 cost time:20s
          orient:01110 cost time:23s
          orient:01111 cost time:20s
          orient:10000 cost time:24s
          orient:10001 cost time:24s
          orient:10010 cost time:24s
          orient:10011 cost time:24s
          orient:10100 cost time:24s
          orient:10101 cost time:24s
          orient:10110 cost time:24s
          orient:10111 cost time:24s
          orient:11000 cost time:24s
          orient:11001 cost time:24s
          orient:11010 cost time:24s
          orient:11011 cost time:24s
          orient:11100 cost time:24s
          orient:11101 cost time:24s
          orient:11110 cost time:24s
          orient:11111 cost time:24s


          # re: 百度面試題目的答案[原創][未登錄]  回復  更多評論   

          2007-10-31 15:18 by javaa
          又學到東西了^_^

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2007-11-14 09:21 by 王者之劍
          thinker是高手,一分鐘內可以解決的問題,有人寫這么長程序
          (看不懂的,你們完了,哈哈,開玩笑的)

          # re: 百度面試題目的答案[原創]  回復  更多評論   

          2008-04-01 10:54 by xiepan

          #include <iostream>
          #include <vector>
          #include <cmath>
          #include <bitset>

          using namespace std;

          typedef struct tagANT
          {
          int pos;
          bool bleft;
          }ANT;

          vector<ANT> vAnts(5);

          void InitAntsState(int seed)
          {
          bitset<5> bit(seed);

          for(int i=0; i<(int)vAnts.size(); i++)
          {
          if(!bit.test(i))
          vAnts[i].bleft = true;
          else
          vAnts[i].bleft = false;
          }

          vAnts[0].pos = 3;
          vAnts[1].pos = 7;
          vAnts[2].pos = 11;
          vAnts[3].pos = 17;
          vAnts[4].pos = 23;
          }

          int main()
          {
          for(int seed = 0; seed <= 31; seed ++)
          {
          InitAntsState(seed);

          int nTimeTicked = 0;
          while (true)
          {
          int nAntsExitNum = 0;
          for(int i=0; i<(int)vAnts.size(); i++)
          {
          if(vAnts[i].pos >=0 && vAnts[i].pos <= 27)
          nAntsExitNum ++;

          if( ((i+1) < (int)vAnts.size()) && (vAnts[i].bleft != vAnts[i+1].bleft)
          && (abs(vAnts[i].pos - vAnts[i+1].pos) == 1))
          {
          vAnts[i].bleft = !vAnts[i].bleft;
          vAnts[i+1].bleft = !vAnts[i+1].bleft;
          }

          if(vAnts[i].bleft)
          {
          vAnts[i].pos --;
          }
          else
          {
          vAnts[i].pos ++;
          }
          }

          if(nAntsExitNum == 0)
          break;

          nTimeTicked++;
          }

          bitset<5> bits(seed);
          for(int i=0; i<5; i++)
          {
          if(!bits.test(i))
          {
          cout << "L, ";
          }
          else
          {
          cout << "R, ";
          }
          }

          cout << " <time " << nTimeTicked << " sec>" << endl;
          }


          cin.get();
          }
          主站蜘蛛池模板: 金湖县| 宜春市| 邮箱| 开封县| 福海县| 高安市| 芦溪县| 合川市| 孝感市| 巴东县| 余庆县| 金阳县| 山东省| 民县| 阿合奇县| 刚察县| 社旗县| 淮安市| 桐梓县| 扎赉特旗| 洪湖市| 元氏县| 南昌县| 潼关县| 山阴县| 武平县| 宁陵县| 商丘市| 自治县| 旺苍县| 保山市| 台江县| 宜良县| 高雄县| 科技| 开阳县| 弥勒县| 镇平县| 嘉定区| 武强县| 璧山县|