問題描述
1.五我的打算過一座吊橋,開始時他們都位於該橋的一側。算法
2.天很黑,五我的手裏只有一個手電筒。app
3.該橋一次最多隻能同時過兩我的,不管是一我的仍是兩我的過橋,都須要攜帶手電筒看路。並且手電筒只能經過人攜帶過橋的方式傳遞。ide
4.第一我的過橋須要1分鐘時間,第二我的過橋須要2分鐘,第三我的須要5分鐘,第四個須要7分鐘,第五個須要10分鐘。因爲速度不一樣,兩我的一塊兒過橋的話,速度以慢的人爲準。spa
問題:求最快過橋時間。要求寫出求解的算法。
分析題目
1.從左邊到右邊,須要有一我的拿着手電筒,到達右邊後,須要有一我的折返回到左邊,那麼怎麼才能最大化的減小返回時間?.net
答:那麼這個送回手電筒的人必定是右邊最快的。日誌
2.兩人同時過橋,取最大時間,那怎麼才能保證最大化的利用最長時間呢?code
答:在左邊選最長時間的兩我的一塊兒過橋。xml
3.怎麼保證右邊折返回來回左邊的人所花的時間最短?對象
答:左邊選擇最快的兩我的一塊兒到右邊,而後最快的折返回左邊,次快的等待最慢的兩我的過來後,再折返回左邊。重複這個步驟便可保證折返回左邊的人所花的時間最短。blog
咱們來試着算一下,最短鬚要多長時間。
(1)選擇左邊最快的兩我的先過去,1分鐘和2分鐘的先過去,總共花費2分鐘。如今左邊5,7,10。右邊1,2。
(2)選擇右邊最快的一我的折返回來,1分鐘的回來,總共花費2分鐘+1分鐘=3分鐘。如今左邊5,7,10。右邊2。
(3)選擇左邊最慢的兩我的過去,7分鐘的和10分鐘的過去,總共花費3分鐘+10分鐘=13分鐘。如今左邊5,1。右邊2,7,10。
(4)選擇右邊最快的一我的折返回來,2分鐘的回來,總共花費13分鐘+2分鐘=15分鐘。如今左邊5,1,2。右邊7,10。
(5)選擇左邊最快的兩我的先過去,1分鐘和2分鐘的先過去,總共花費15分鐘+2分鐘。如今左邊5。右邊7,10,1,2。
(6)選擇右邊最快的一我的折返回來,1分鐘的回來,總共花費17分鐘+1分鐘=18分鐘。如今左邊5,1。右邊7,10,2。
(5)選擇左邊最慢的兩我的過去,5分鐘的1分鐘的過去,總共花費18分鐘+5分鐘=23分鐘。如今左邊沒有。右邊7,10,2,5,1。
總共花費23分鐘。
總結一下上面的規律:
最快的兩我的過去,最快一我的回來,最慢的兩我的過去,最快的一我的回來。循環這個步驟。
怎麼實現上面的算法?
這裏咱們能夠用面向對象的方法。
定義一個Person類。
包含的屬性:
(1)過橋速度Speed。(1分鐘/2分鐘/5分鐘/7分鐘/10分鐘)
(2)當前在橋的哪一邊Side(左邊/右邊)
包含的方法:從左邊走到右邊的方法,或者從右邊折返回左邊的方法,命名爲Pass(Side side);
定義一個接口IPassAction,包含一個方法void Pass(Side side);
定義一個枚舉類型Side,包含Left、Right
定義一個方法,在某一邊找過橋速度最慢的兩我的
List<Person> FindTwoFastSpeedPersons(List<Person> persons, Side side)
定義一個方法,在某一邊找過橋速度最快的兩我的
List<Person> FindTwoLowestSpeedPersons(List<Person> persons, Side side)
定義一個方法,在某一邊找過橋速度最慢的兩我的
Person FindFastSpeedPerson(List<Person> persons, Side side)
定義一個方法,檢測是否指定的person到達了指定的一邊
CheckPersonsPassedToTargetSide(List<Person> persons, Side targetSide)
代碼
Person類
namespace PassRiver2._0 { public class Person : IPassAction { private int _speed; private Side _side; public Person(int speed, Side side) { _speed = speed; _side = side; } public int Speed { get { return _speed; } set { _speed = value; } } public Side Side { get { return _side; } set { _side = value; } } public void Pass(Side side) { _side = side; } } }
Side枚舉類
namespace PassRiver2._0 { public enum Side { Left = 0, Right = 1 } }
IPassAction接口
namespace PassRiver2._0 { public interface IPassAction { void Pass(Side side); } }
公共方法
List<Person> FindTwoFastSpeedPersons(List<Person> persons, Side side)
List<Person> FindTwoLowestSpeedPersons(List<Person> persons, Side side)
Person FindFastSpeedPerson(List<Person> persons, Side side)
CheckPersonsPassedToTargetSide(List<Person> persons, Side targetSide)
private static List<Person> FindTwoLowestSpeedPersons(List<Person> persons, Side side) { List<Person> sortedPersons = persons.Where(s=> s.Side == side).OrderByDescending(s => s.Speed).ToList(); List<Person> passedPersons = new List<Person>(); if (persons.Count > 1) { passedPersons = new List<Person>(); passedPersons.Add(sortedPersons[0]); passedPersons.Add(sortedPersons[1]); } else if (persons.Count == 1) { passedPersons.Add(sortedPersons[0]); } else { } return passedPersons; } private static List<Person> FindTwoFastSpeedPersons(List<Person> persons, Side side) { List<Person> sortedPersons = persons.Where(s=> s.Side == side).OrderBy(s => s.Speed).ToList(); List<Person> passedPersons = new List<Person>(); if (persons.Count > 1) { passedPersons = new List<Person>(); passedPersons.Add(sortedPersons[0]); passedPersons.Add(sortedPersons[1]); } else if (persons.Count == 1) { passedPersons.Add(sortedPersons[0]); } else { return null; } return passedPersons; } private static Person FindFastSpeedPerson(List<Person> persons, Side side) { if (persons.Count > 0) { List<Person> sortedPersons = persons.Where(s => s.Side == side).OrderBy(s => s.Speed).ToList(); return sortedPersons[0]; } else { return null; } } private static bool CheckPersonsPassedToTargetSide(List<Person> persons, Side targetSide) { bool isPassed = false; foreach (Person person in persons) { if (person.Side != targetSide) { isPassed = false; return isPassed; } } isPassed = true; return isPassed; }
Main方法
static void Main(string[] args) { Type type = MethodBase.GetCurrentMethod().DeclaringType; //建立日誌記錄組件實例 ILog log = log4net.LogManager.GetLogger(type); //記錄錯誤日誌 log.Info("Start"); List<Person> persons = new List<Person>(); persons.Add(new Person(1, Side.Left)); persons.Add(new Person(2, Side.Left)); persons.Add(new Person(5, Side.Left)); persons.Add(new Person(7, Side.Left)); persons.Add(new Person(10, Side.Left)); int totalTime = 0; while (!CheckPersonsPassedToTargetSide(persons, Side.Right)) { List<Person> twoFastSpeedPersons = FindTwoFastSpeedPersons(persons, Side.Left); foreach (Person person in twoFastSpeedPersons) { person.Pass(Side.Right); } if (twoFastSpeedPersons.Count > 1) { totalTime += twoFastSpeedPersons[1].Speed; } else if (twoFastSpeedPersons.Count == 1) { totalTime += twoFastSpeedPersons[0].Speed; } else { } //------------- log.Info("---Go To Right---------->"); foreach (Person person in twoFastSpeedPersons) { log.Info(person.Speed); } log.Info("Total Time:" + totalTime); //------------- if (CheckPersonsPassedToTargetSide(persons, Side.Right)) { break; } Person fastSpeedPerson = FindFastSpeedPerson(persons, Side.Right); fastSpeedPerson.Pass(Side.Left); totalTime += fastSpeedPerson.Speed; //------------- log.Info("<----------Go Back Left---"); log.Info(fastSpeedPerson.Speed); log.Info("Total Time:" + totalTime); //------------- if (CheckPersonsPassedToTargetSide(persons, Side.Right)) { break; } List<Person> twoLowestSpeedPersons = FindTwoLowestSpeedPersons(persons, Side.Left); foreach (Person person in twoLowestSpeedPersons) { person.Pass(Side.Right); } totalTime += twoLowestSpeedPersons[0].Speed; //------------- log.Info("---Go To Right---------->"); foreach (Person person in twoLowestSpeedPersons) { log.Info(person.Speed); } log.Info("Total Time:" + totalTime); //------------- if (CheckPersonsPassedToTargetSide(persons, Side.Right)) { break; } fastSpeedPerson = FindFastSpeedPerson(persons, Side.Right); fastSpeedPerson.Pass(Side.Left); totalTime += fastSpeedPerson.Speed; //------------- log.Info("<----------Go Back Left---"); log.Info(fastSpeedPerson.Speed); log.Info("totalTime:" + totalTime); //------------- if (CheckPersonsPassedToTargetSide(persons, Side.Right)) { break; } } log.Info("------------Total Time-------------"); log.Info(totalTime); Console.ReadKey(); }
Log4Net配置:
<?xml version="1.0"?> <configuration> <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/> </configSections> <!--站點日誌配置部分--> <log4net> <root> <!--控制級別,由低到高: ALL|DEBUG|INFO|WARN|ERROR|FATAL|OFF--> <!--好比定義級別爲INFO,則INFO級別向下的級別,好比DEBUG日誌將不會被記錄--> <!--若是沒有定義LEVEL的值,則缺省爲DEBUG--> <level value="DEBUG"/> <appender-ref ref="PassRiverLogger2"/> </root> <appender name="PassRiverLogger2" type="log4net.Appender.ConsoleAppender"> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" /> </layout> </appender> </log4net> </configuration>
結果:
注意:
這種算法只適合部分狀況。好比5我的的過橋速度是1分鐘、10分鐘、11分鐘、12分鐘、13分鐘,則用這種算法算出來的56分鐘。可是若是1分鐘和其餘四我的分別過橋,每次都是1分鐘的回來,則總時間是10+11+12+13+1*3=49(分鐘)。
本文同步分享在 博客「7年一線互聯網經驗,超愛圖解底層原理,全棧一枚」(CNBlog)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。