|
Posted on 2006-11-10 16:46 itspy 閱讀(11882) 評(píng)論(52) 編輯 收藏 所屬分類: 小巧實(shí)例 、 JAVA技術(shù)
最近有同學(xué)找工作,經(jīng)常在班級(jí)群里發(fā)一些大公司的面試,筆試題目.昨天收到這樣一個(gè)題目,據(jù)說是百度的面試題目.
?有一根27厘米的細(xì)木桿,在第3厘米、7厘米、11厘米、17厘米、23厘米這五個(gè)位置上各有一只螞蟻。 木桿很細(xì),不能同時(shí)通過一只螞蟻。開始 時(shí),螞蟻的頭朝左還是朝右是任意的,它們只會(huì)朝前走或調(diào)頭, 但不會(huì)后退。當(dāng)任意兩只螞蟻碰頭時(shí),兩只螞蟻會(huì)同時(shí)調(diào)頭朝反方向走。假設(shè)螞蟻們每秒鐘可以走一厘米的距離。 編寫程序,求所有螞蟻都離開木桿 的最小時(shí)間和最大時(shí)間。
看了這個(gè)題目之后,突然很感興趣,今天搞了半天把它做出來了,大概花了1個(gè)半小時(shí).大公司的題目真是考人.反正都已經(jīng)用算法實(shí)現(xiàn)了,我就不多說了,大家看代碼吧.代碼里面注釋我也盡量全寫了.一共有兩個(gè)類,一個(gè)是Ant的模型,一個(gè)是控制類.原代碼,大家可以在這取得:
http://m.tkk7.com/Files/itspy/baidu.rar
////////////////////////////////////// /*百度面試題 ?* 有一根27厘米的細(xì)木桿,在第3厘米、7厘米、11厘米、17厘米、23厘米這五個(gè)位置上各有一只螞蟻。 ?* 木桿很細(xì),不能同時(shí)通過一只螞蟻。開始 時(shí),螞蟻的頭朝左還是朝右是任意的,它們只會(huì)朝前走或調(diào)頭, ?* 但不會(huì)后退。當(dāng)任意兩只螞蟻碰頭時(shí),兩只螞蟻會(huì)同時(shí)調(diào)頭朝反方向走。假設(shè)螞蟻們每秒鐘可以走一厘米的距離。 ?* 編寫程序,求所有螞蟻都離開木桿 的最小時(shí)間和最大時(shí)間。 ?* ?* ?* 分析:題目中的螞蟻只可能相遇在整數(shù)點(diǎn),不可以相遇在其它點(diǎn),比如3.5cm處之類的,也就是可以讓每只螞蟻?zhàn)?1秒,然后 ?* 查看是否有相遇的即可. ?* ?* 這樣我的程序?qū)崿F(xiàn)思路就是,初始化5只螞蟻,讓每只螞蟻?zhàn)?秒,然后看是否有相遇的,如果有則做相應(yīng)處理.當(dāng)每只螞蟻都 ?* 走出木桿時(shí),我就記錄當(dāng)前時(shí)間.這樣就可以得到當(dāng)前狀態(tài)情況下,需要多久可以走出木桿,然后遍歷所有狀態(tài)則可以得到所胡 ?* 可能. ?*/
package baidu;
public class Ant { ?/* ? * step 表示螞蟻每一個(gè)單位時(shí)間所走的長(zhǎng)度 ? */ ?private final static int step = 1;
?/* ? * position表示螞蟻所處的初始位置 ? */ ?private int position;
?/* ? * direction表示螞蟻的前進(jìn)方向,如果為1表示向27厘米的方向走, 如果為-1,則表示往0的方向走。 ? */ ?private int direction = 1;
?/* ? * 此函數(shù)運(yùn)行一次,表示螞蟻前進(jìn)一個(gè)單位時(shí)間,如果已經(jīng)走下木桿則會(huì)拋出異常 ? */ ?public void walk() { ??if (isOut()) { ???throw new RuntimeException("the ant is out"); ??} ??position = position + this.direction * step; ?};
?/** ? * 檢查螞蟻是否已經(jīng)走出木桿,如果走出返回true ? * ? */
?public boolean isOut() { ??return position <= 0 || position >= 27; ?}
?/** ? * 檢查此螞蟻是否已經(jīng)遇到另外一只螞蟻 ? * @param ant ? * @return 如果遇到返回true ? */ ?public boolean isEncounter(Ant ant) { ??return ant.position == this.position; ?}
?/** ? * 改變螞蟻的前進(jìn)方向 ? */ ?public void changeDistation() { ??direction = -1 * direction; ?}
?/** ? * 構(gòu)造函數(shù),設(shè)置螞蟻的初始前進(jìn)方向,和初始位置 ? * @param position ? * @param direction ? */ ?public Ant(int position, int direction) { ??this.position = position; ??if (direction != 1) { ???this.direction = -1;//方向設(shè)置初始位置,比如為0時(shí),也將其設(shè)置為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++; ????// 查看是否有已經(jīng)相遇的Ant,如果有則更改其前進(jìn)方向 ????dealEncounter(antArray); ???} ???System.out.println(time);
???// 將時(shí)間歸0,這樣可以重新設(shè)置條件,再次得到全部走完所需要的時(shí)間. ???time = 0; ??}
?}
?/** ? * 這個(gè)函數(shù)的算法很亂,但暫時(shí)能解決問題 ? * ? * @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(); ????} ???} ??}
?}
?/** ? * 因?yàn)橛?只Ant,所以組合之后有32種組合.剛好用5位二進(jìn)制來表示,如果為0則表示Ant往0的方向走 如果為1,則表示往27的方向走 ? * ? * 注:在通過Ant的構(gòu)造函數(shù)設(shè)置初始值時(shí),通過過濾把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;
?}
?/** ? * 批量設(shè)置Ant的初始位置,這樣設(shè)置不是十分必要,可以直接在代碼中設(shè)置 ? * ? * @return ? */ ?public static int[] getPoistions() { ??return new int[] { 3, 7, 11, 17, 23 }; ?}
?/** ? * 取得設(shè)置好初始值的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都已經(jīng)走出了木桿,也就是設(shè)置退出條件 ? * ? * @param antArray ? * @return ? */ ?public static boolean isAllOut(Ant[] antArray) { ??for (Ant ant : antArray) { ???if (ant.isOut() == false) { ????return false; ???} ??} ??return true; ?} }
?
評(píng)論
dealEncounter這里。
不相鄰的螞蟻是不會(huì)相遇的。
是的,這個(gè)dealEncounter有很大改進(jìn)的空間.不過你剛才說的這個(gè)我之前沒有考慮到.
我之前只是考慮到了:有一些螞蟻已經(jīng)走出了木桿,就不用去處理了.不過實(shí)現(xiàn)起來有些不太方便.就沒有去處理了.
所以在注釋中,我也說明了這個(gè)dealEncounter肯定可以進(jìn)行.
謝謝你的評(píng)論
改進(jìn)后的dealEncounter為,謝謝差沙的回復(fù)
/**
* 這個(gè)函數(shù)的算法很亂,但暫時(shí)能解決問題
*
* @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();
}
}
}
/*百度面試題
* 有一根27厘米的細(xì)木桿,在第3厘米、7厘米、11厘米、17厘米、23厘米這五個(gè)位置上各有一只螞蟻。
* 木桿很細(xì),不能同時(shí)通過一只螞蟻。開始 時(shí),螞蟻的頭朝左還是朝右是任意的,它們只會(huì)朝前走或調(diào)頭,
* 但不會(huì)后退。當(dāng)任意兩只螞蟻碰頭時(shí),兩只螞蟻會(huì)同時(shí)調(diào)頭朝反方向走。假設(shè)螞蟻們每秒鐘可以走一厘米的距離。
* 編寫程序,求所有螞蟻都離開木桿 的最小時(shí)間和最大時(shí)間。
*
*/
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();//開始運(yùn)行
System.out.println("總共用時(shí):"+calculate.sumTime());
}
}
public class Ant implements Subject,Runnable {
private long position;//位置
private String name;//名字
private int rate;//速度
private int useTime;//走完全程用時(shí)
private boolean isStop;//停止,說明是否已經(jīng)走出木桿,是則true,否則false
private boolean forWord;//螞蟻的前進(jìn)方向false為負(fù),true為正
//private int distance;//每次的間隔的路程
private List observers =new ArrayList();
private Ant frontAnt;//前一個(gè)螞蟻
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;
}
//改變螞蟻的前進(jìn)方向,當(dāng)和前一個(gè)螞蟻相遇時(shí)就兩只螞蟻都調(diào)頭
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;
}
}
public interface Observer {
public void update(Subject object)throws Exception;
}
/*
* 抽像層,提供了要加入計(jì)算的對(duì)象集合,繼承的子類要實(shí)現(xiàn)他們自已的運(yùn)算規(guī)則
*/
public abstract class EveryCalculate {
protected List calculates=new ArrayList();//每個(gè)要計(jì)算的對(duì)象
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 ();
}
public interface Subject {
public void attach(Observer observer);
public void detach(Observer observer);
public void notifyObservers()throws Exception;
}
/*
* 實(shí)現(xiàn)運(yùn)算規(guī)則
*/
public class AntSubjectCalculate extends EveryCalculate implements Observer {
private final int length;
private final long incrementTime;//表示螞蟻前進(jìn)一個(gè)單位時(shí)間,間隔時(shí)間以毫秒計(jì)算
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;//在算法中確定他的前后節(jié)點(diǎn)
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();
//當(dāng)兩個(gè)螞蟻?zhàn)叩酵稽c(diǎn)時(shí)就轉(zhuǎn)向
if(frontAnt!=null && frontAnt.getPosition()>= ant.getPosition()){
System.out.println("螞蟻:"+ant.getName()+"和"+frontAnt.getName()+"轉(zhuǎn)向了!");
ant.inverse();
frontAnt.inverse();
}
if(ant.getPosition() >= this.getLength() || ant.getPosition() <= 0){
ant.seIsStop(true);//停止這個(gè)螞蟻的行動(dòng)!
if(ant.getUseTime()>this.useTime){
this.useTime = ant.getUseTime();//保存最后一只螞蟻的時(shí)間
}
System.out.println("螞蟻:"+ant.getName()+"已出木桿,用時(shí):" + ant.getUseTime());
}
System.out.println("螞蟻:"+ant.getName()+"位置"+ant.getPosition());
}
//這個(gè)方法也可移出去,作為一個(gè)外層的控制觸了器來用,主要模擬螞蟻開始行走的情況
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;
}
}
我是用觀察者模式實(shí)現(xiàn)的。實(shí)現(xiàn)之前,沒有看原創(chuàng)的實(shí)現(xiàn),只按自已的想法寫了這段代碼!不是為了比較誰好誰壞,只不過想了表一下自已的一些見解,因?yàn)榇a是相通的,只是實(shí)現(xiàn)手法不一相而已。歡迎相互交流,我的郵箱是yoohoo.lai@163.com
外面代碼入口在public class TestMain 之中,由于沒加更多注釋.可能看起來有點(diǎn)費(fèi)力
@路過
之前我也想過用觀察者模式來實(shí)現(xiàn),但是在最后寫出了Ant的模式之后,發(fā)現(xiàn)不用這個(gè)模式也很容易實(shí)現(xiàn),也就沒有用這個(gè)模式了.
謝謝討論
其實(shí)代碼的實(shí)現(xiàn),是有多種方法的,但如果百度的題目改一下可能要用N只螞蟻,用不同的速度離開時(shí),這時(shí)侯,就可能要改算法,而我實(shí)現(xiàn)這個(gè)的目的就在于,如果提出了這個(gè)要求我只要,另寫一個(gè)實(shí)現(xiàn)算法就能實(shí)現(xiàn)另外的題目public class *Calculate extends EveryCalculate implements Observer
而不用更改其它代碼!這也是我為什么會(huì)考慮用觀察者實(shí)現(xiàn)的原因了!
不相鄰的螞蟻,我的做法是直接在Ant類中用鏈表結(jié)構(gòu)定義的。其實(shí)細(xì)仔想起來這個(gè)這一層應(yīng)該跟業(yè)務(wù)對(duì)象隔離開來!螞蟻的排列規(guī)則,應(yīng)該在寫一個(gè)接口和實(shí)現(xiàn)類去定義,這樣當(dāng)改變排列順序的時(shí)侯也只要多寫一個(gè)實(shí)現(xiàn)類而已!
你說的很對(duì),其實(shí)之前我也考慮過這個(gè)問題,百度剛好把Ant放置在了幾個(gè)特別的位置.這時(shí)幾個(gè)Ant只可能在整數(shù)點(diǎn)相遇.比如要是有一個(gè)Ant在5處,有一個(gè)在8處.這時(shí)我們實(shí)現(xiàn)時(shí),可能就不能一厘米一厘米的走了.
不錯(cuò),你的實(shí)現(xiàn)確實(shí)比我要好多了.
樓上的兄弟們,你們是不是把問題復(fù)雜化了??
如果五個(gè)螞蟻?zhàn)畛醯臓顟B(tài)已經(jīng)確定,那么全部離開木桿的時(shí)間已經(jīng)確定。所以問題的關(guān)鍵是如何決定螞蟻?zhàn)畛醯臓顟B(tài)。
1.把木桿根據(jù)中點(diǎn)分為左半部分和右半部分。
2.作為一只螞蟻,要想最快地離開木桿,首先是判斷自己屬于木桿的哪部分。如果是左,則向左走;如果是右,就向右走。這樣就可最快地離開木桿。
3.如果是想最慢地離開木桿,只需改成相反規(guī)則就可:如果是左,則向右走;如果是右,就向左走。這個(gè)有點(diǎn)意思,可能有人懷疑,真的是這樣嗎?
問題就是這么簡(jiǎn)單,呵呵。
@xinheqishi
樓上說的第3點(diǎn),在這個(gè)場(chǎng)景中是對(duì)的,但不知道如何去證明他的通用性.如第3點(diǎn)不成立的話,則只好使用遍歷去找出所有的時(shí)間了.
通過遍歷查找,有32種可能的方向組合,但有16種"并列"為最慢.
當(dāng)然,最快的只有一種,就是你說的那種
哪個(gè)能想辦法證明一下這一點(diǎn)嗎?
3.如果是想最慢地離開木桿,只需改成相反規(guī)則就可:如果是左,則向右走;如果是右,就向左走。這個(gè)有點(diǎn)意思,可能有人懷疑,真的是這樣嗎?
通過算各個(gè)螞蟻運(yùn)動(dòng)的路程可以算出每個(gè)螞蟻的運(yùn)動(dòng)時(shí)間
主要控制部分:
int[] pos ={ 3, 7, 11, 17, 23 }; //位置
ArrayList antlist = new ArrayList(); //存放運(yùn)行中螞蟻
Random ran = new Random();
foreach (int p in pos)
{
int speed = ran.Next(11) % 2 == 0 ? 1 : -1; //隨機(jī)方向,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++) //判斷此時(shí)是否有相遇的,如有,各自掉頭
{
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; //運(yùn)動(dòng)總距離
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;
}
}
}
大致算了下,好象沒錯(cuò)誤。c#編寫
覺得此題比較有迷惑性,螞蟻碰頭后各自掉頭,實(shí)際整個(gè)過程中螞蟻都在運(yùn)動(dòng),如果能算出螞蟻?zhàn)叩目偮烦蹋敲次浵伒倪\(yùn)動(dòng)時(shí)間也就能得出。覺得這樣算法會(huì)簡(jiǎn)單許多
樓上說的觀點(diǎn)和我的初衷的出發(fā)點(diǎn)是不一樣的,如果就是了解決這個(gè)問題其實(shí)方法可以很簡(jiǎn)單,這個(gè)題目不就為了算出五只螞蟻離開一個(gè)桿子嗎?其實(shí)只要抓住一點(diǎn)就行,就是比較最后一只離開桿子的螞蟻?zhàn)叩目偟穆烦叹涂梢粤?。路程最短的也就最快,路程最大的就最慢!?yīng)用數(shù)學(xué)上一些算法就能解決。這根本用不著一個(gè)一個(gè)按間隔時(shí)間遍歷,耗這個(gè)性能在里面。
之所以用模式的東西去解決問題,其實(shí)是把這道題模擬了一下螞蟻的行走的場(chǎng)景。注重的是他的擴(kuò)展性,而不是算法本身!
所以從算法的角度來講這個(gè)是把簡(jiǎn)單的東西復(fù)雜化,這是沒必要的!從軟件的開閉原則來講,這些也不算什么!
哪個(gè)能想辦法證明一下這一點(diǎn)嗎?
3.如果是想最慢地離開木桿,只需改成相反規(guī)則就可:如果是左,則向右走;如果是右,就向左走。這個(gè)有點(diǎn)意思,可能有人懷疑,真的是這樣嗎?
×××××××××××××××××××××××××××××××××××××××××
樓主你好,我是憑著對(duì)數(shù)學(xué)的一種直覺得出這個(gè)結(jié)論的。并沒有經(jīng)過嚴(yán)格的證明,忽悠了一下樓主,呵呵。見笑見笑!
當(dāng)時(shí)我是這么想的,把左邊的所有螞蟻?zhàn)鳛橐粋€(gè)整體,右邊的作為一個(gè)整體,哪么這個(gè)情形就跟木桿上只有兩只螞蟻的情形就一樣了。這是從純數(shù)學(xué)的角度去思考。
我覺得從解決問題的角度,應(yīng)該是這種思路,直奔主題。簡(jiǎn)單的問題就盡量用簡(jiǎn)單的方法解決。
Java編程方面,我只是一個(gè)初學(xué)者,我還得謝謝樓主,讓我又多學(xué)了點(diǎn)。
之所以用模式的東西去解決問題,其實(shí)是把這道題模擬了一下螞蟻的行走的場(chǎng)景。注重的是他的擴(kuò)展性,而不是算法本身!
×××××××××××××××××××××××××××××××××××××××××
從學(xué)東西的角度,我是認(rèn)可這個(gè)觀點(diǎn)的。
模擬了一下螞蟻的行走的場(chǎng)景。
關(guān)于這點(diǎn),我當(dāng)時(shí)還有這么一個(gè)想法:設(shè)計(jì)兩個(gè)類,一個(gè)是螞蟻,一個(gè)是木桿。
木桿用來記錄狀態(tài),如某點(diǎn)上的值為0表示該點(diǎn)上沒有螞蟻,為1表示有一個(gè)螞蟻,為2表示有兩個(gè)螞蟻(即碰撞)。螞蟻從A走到B,A上的值減1,B上的值加1。木桿上只要發(fā)生有X點(diǎn)值為2的情況,馬上就讓X點(diǎn)的兩個(gè)螞蟻調(diào)頭。
問下大家這個(gè)思路是否可行?
整理成模式應(yīng)該不是件難事把,既然是面視的題目,就要簡(jiǎn)單快速的解決問題,這才是重要
樓上的兄弟,實(shí)話說,Java方面我只是個(gè)新手,設(shè)計(jì)模式也還沒怎么接觸,不過挺有興趣的。還請(qǐng)兄弟多指教。你的代碼我看了,感覺我的思路跟你的觀察者模式是類似的。木桿就相當(dāng)于是個(gè)觀察者了吧?
樓上說的第3點(diǎn),在這個(gè)場(chǎng)景中是對(duì)的,但不知道如何去證明他的通用性.如第3點(diǎn)不成立的話,則只好使用遍歷去找出所有的時(shí)間了.
通過遍歷查找,有32種可能的方向組合,但有16種"并列"為最慢.
當(dāng)然,最快的只有一種,就是你說的那種
============
最快的擺放
1.把木桿根據(jù)中點(diǎn)分為左半部分和右半部分。
2.作為一只螞蟻,要想最快地離開木桿,首先是判斷自己屬于木桿的哪部分。如果是左,則向左走;如果是右,就向右走。這樣就可最快地離開木桿。
最慢的擺放
1, 除非在中點(diǎn),每只螞蟻離開木桿都有一個(gè)近端距離, 遠(yuǎn)端距離
2, 只要保證5只螞蟻中 遠(yuǎn)端距離最長(zhǎng)的螞蟻面向遠(yuǎn)端, 其他的螞蟻隨便擺放即可。 所以在"32種可能的方向組合,有16種并列為最慢".
程序懶得寫了 最多10行解決問題
回復(fù)樓上:
我想這個(gè)題目讓人來做,肯定比電腦快.所以樓上才能這么游刃有余的這樣分析,找出答案 .
1)你如何讓程序找出:5只螞蟻中哪個(gè)的遠(yuǎn)端距離最長(zhǎng)?
2)遠(yuǎn)端距離如何定義?要知道每只螞蟻的方向的改變最終可能都會(huì)影響到其它的螞蟻的爬行距離.遠(yuǎn)端距離可能并不好算.
這兩個(gè)問題我不大會(huì)解決,更不用說10行代碼了,這個(gè)請(qǐng)樓幫忙說清楚些,或者是其它有人明白的,講講也行.
以題目為例
"有一根27厘米的細(xì)木桿,在第3厘米、7厘米、11厘米、17厘米、23厘米這五個(gè)位置上各有一只螞蟻"
3cm 的 (近端3,遠(yuǎn)端24)
7 (7,20)
11 (11,16)
17 (10,17)
23 (4,23)
所以只要保證3 厘米的螞蟻面向24的一端 其他的螞蟻隨便擺
把碰撞簡(jiǎn)化成AB相遇延a,b原方向繼續(xù)前進(jìn),即可求出最大時(shí)間 就是最大的遠(yuǎn)端距離/速度。
詞解法可以用于任意位置 任意速度, 但必須保證每個(gè)螞蟻速度相同
樓上的解法十分簡(jiǎn)單明白,不過我還是有些不解^_^。
于是想找個(gè)反例,但找了半天,也沒找到。
沒有反例的啦, 哪怕有10000只螞蟻在上面, 只要保證最遠(yuǎn)端的螞蟻面向遠(yuǎn)端, 最長(zhǎng)的時(shí)間就是最遠(yuǎn)端/速度。
這道題最大的迷惑項(xiàng) 是相撞, 如果轉(zhuǎn)換成只是相遇,擦肩而過就好理解了,并且這種轉(zhuǎn)化不影響結(jié)果。
假設(shè)A B相向而行,A距遠(yuǎn)端的距離為a, B為b, A B各自走了距離c以后相遇,碰撞,反向, A要走(b-c)距離, B要走(a-c), 總共A走了b, B走了a距離。所以max(a,b)就是最遠(yuǎn)距離,相撞還是擦肩而過只是影響到是A走了a還是走了b, 對(duì)整體答案沒有影響。
應(yīng)該可以有更縝密的數(shù)學(xué)推理,我的數(shù)學(xué)很差,就不獻(xiàn)丑了。
這道題最大的迷惑項(xiàng) 是相撞, 如果轉(zhuǎn)換成只是相遇,擦肩而過就好理解了。
可能大部分看過這個(gè)帖子的人都被這個(gè)迷惑。反正我是被迷惑了。
呵呵,這個(gè)題目有意思,看上去復(fù)雜,其實(shí)簡(jiǎn)單。我的理解是如果螞蟻轉(zhuǎn)身不需要時(shí)間,而且所有的螞蟻都長(zhǎng)得一樣,而且我眼神也不好的話,那么兩只螞蟻是碰撞還是擦肩而過,看上去都一樣,反正我看到的先是兩個(gè)黑點(diǎn)靠近,然后這兩個(gè)黑點(diǎn)碰到一起,然后又分開。
好多聰明人,thinker果然是個(gè)思考者.
高! thinker 是個(gè)高人啊,能夠看到本質(zhì)問題。
高?。?!
這才叫解決問題呢。。。
編碼編了變天,都看不懂,屁用?。。?/div>
/**
* 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;
}
}
俺上面的代碼沒寫注釋,但相信有一定編程經(jīng)驗(yàn)的很容易看懂.關(guān)鍵的一個(gè)地方就是5個(gè)螞蟻的方向就是2的5次方種可能,故用0-31的2進(jìn)制數(shù)的對(duì)應(yīng)位是1還是0來表示方向.
其實(shí)編程歸編程,其實(shí)還有個(gè)更深刻的原理.就是樓上各位已經(jīng)分析過的.
1:微觀上看a螞蟻和b螞蟻相遇后是調(diào)頭了.即a現(xiàn)在是沿著b本應(yīng)該走的路走了,b沿著a本應(yīng)該走的路繼續(xù)走.
2:宏觀上如果把a(bǔ)螞蟻和b螞蟻看成是完全一樣的螞蟻,那么相當(dāng)于兩個(gè)螞蟻都沒有調(diào)頭.
3:如果一時(shí)想不明白,可以想最簡(jiǎn)單的情形,就只有兩只螞蟻從棍子兩端相向而行,在中間遇到后調(diào)頭,是不是跟沒調(diào)頭一樣呢???
4:這就是有名的鬼魂理論,跟物理上的動(dòng)量守恒很類似.
數(shù)學(xué)歸納證明來了...
1:假設(shè)如果不碰頭,有一個(gè)螞蟻a0的需要走的距離為S0.時(shí)間為t0,所有螞蟻速度為v,則s0=v*t0.同理,還有一個(gè)螞蟻a1,需要走的距離為S1,時(shí)間為t1, s1= v*t1.
2:當(dāng)a0遇到a1的時(shí)候,假設(shè)走了t秒,a1剩的距離為s0-v*t.因此a1剩的距離為v*t0-v*t,剩下的時(shí)間為t0-t,恰好為a0本來走到頭需要的時(shí)間.因此此時(shí)a1總共需要走出的時(shí)間為t0.而a0需要走出的時(shí)間總共為t1.
3:一般來說,當(dāng)螞蟻aN遇到a(N+1)的時(shí)候,aN原本需要的總共的時(shí)間tN被賦給了a(N+1),而t(N+1)被賦給了aN.
4:因此n只螞蟻如果遇到不調(diào)頭走出需要的時(shí)間分別為t1,t2,....tN,那么每一次有螞蟻碰頭的時(shí)候,他們需要的時(shí)間仍然為t1,t2,....tN,只是具體哪只螞蟻需要多少時(shí)間可能互相有交換.
5:因此最大最小時(shí)間就是最后一只能走出去的螞蟻的最大最小時(shí)間.
有個(gè)問題,如果所有螞蟻的初始狀態(tài)都確定了,所有走出去應(yīng)該只有一個(gè)時(shí)間,何來最小時(shí)間和最大時(shí)間?
這道題求最長(zhǎng)時(shí)間只能用編程來解決。
Thinker所說的理解看似很對(duì),但有漏洞,我這里只簡(jiǎn)單的舉個(gè)反例吧。
還是長(zhǎng)度27厘米的樹桿,只有三只螞蟻,3厘米有一只,7厘米有一只,25厘米有一只。3厘米向右,7厘米向左,25厘米向左,最后所花時(shí)間為27厘米/速度。
而如果7厘米和25厘米得螞蟻都向右,那么所花時(shí)間為24厘米/速度。
如果按Thinker所說把3厘米的向右,其他隨便擺,怎么找出這兩個(gè)誰大啊,所以還是要遍歷的
@林林
Thinker的理解沒有錯(cuò),是你搞錯(cuò)了一個(gè)地方。Thinker說的是最遠(yuǎn)端的螞蟻朝向遠(yuǎn)端,因此在你的例子里面,應(yīng)該是25厘米的螞蟻朝左,而其他的螞蟻隨便擺,這樣才是最大時(shí)間。
有個(gè)問題,如果所有螞蟻的初始狀態(tài)都確定了,所有走出去應(yīng)該只有一個(gè)時(shí)間,何來最小時(shí)間和最大時(shí)間?
==============================================
題目中說了:螞蟻的頭向左向右是隨機(jī)的,所以初始狀態(tài)不是確定的,這樣就有最小時(shí)間和最大時(shí)間。
toooooooooooooooooooooooooold
就是一個(gè)穿過的問題,不用寫程序,微軟也考過
#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
@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
thinker是高手,一分鐘內(nèi)可以解決的問題,有人寫這么長(zhǎng)程序 (看不懂的,你們完了,哈哈,開玩笑的)
#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();
}
|