妖怪与和尚过河问题

作者:追风剑情 发布于:2015-11-5 21:20 分类:Algorithms

      有三个妖怪和三个和尚要利用唯一一条小船过河,这条小船每次至少载一个人最多载两个人,无论是在河的两岸还是在船上,只要妖怪的数量大于和尚的数量,妖怪们就会将和尚吃掉。现在需要选择一种过河的安排,保证和尚和妖怪都能过河且和尚不能被妖怪吃掉。

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. namespace MonkTest
  7. {
  8. class Program
  9. {
  10. static void Main(string[] args)
  11. {
  12. new AcrossRiver().SearchState();
  13.  
  14. Console.Read();
  15. }
  16. }
  17. }
  18.  
  19.  
  20.  
  21. /// <summary>
  22. /// 过河问题求解类
  23. /// 思路: 把抽象问题转化成计算能处理的数学模型
  24. /// 算法原理:利用状态树求解 (采用深度优先搜索)
  25. /// 效率优化: 采用剪枝、去重
  26. /// </summary>
  27. public class AcrossRiver
  28. {
  29. //过河动作枚举
  30. private enum ActionName
  31. {
  32. //一个妖怪过河
  33. ONE_MONSTER_GO,
  34. //两个妖怪过河
  35. TWO_MONSTER_GO,
  36. //一个和尚过河
  37. ONE_MONK_GO,
  38. //两个和尚过河
  39. TWO_MONK_GO,
  40. //一个妖怪和一个和尚过河
  41. ONE_MONSTER_ONE_MONK_GO,
  42. //一个妖怪返回
  43. ONE_MONSTER_BACK,
  44. //两个妖怪返回
  45. TWO_MONSTER_BACK,
  46. //一个和尚返回
  47. ONE_MONK_BACK,
  48. //两个和尚返回
  49. TWO_MONK_BACK,
  50. //一个妖怪和一个和尚返回
  51. ONE_MONSTER_ONE_MONK_BACK
  52. };
  53.  
  54. //船的行使方向枚举
  55. private enum BoatLocation
  56. {
  57. REMOTE, //对岸
  58. LOCAL //本岸
  59. }
  60.  
  61. //过河动作数学模型
  62. private class ActionEffection
  63. {
  64. public ActionName act;
  65. public BoatLocation boat_to;//船移动的方向
  66. public int move_monster;//此次移动的妖怪数量
  67. public int move_monk;//此次移动的和尚数量
  68.  
  69. public ActionEffection(ActionName act, BoatLocation boat_to, int move_monster, int move_monk)
  70. {
  71. this.act = act;
  72. this.boat_to = boat_to;
  73. this.move_monster = move_monster;
  74. this.move_monk = move_monk;
  75. }
  76. }
  77.  
  78. private class ItemState
  79. {
  80. public int local_monster = 3;
  81. public int local_monk = 3;
  82. public int remote_monster = 0;
  83. public int remote_monk = 0;
  84. public BoatLocation boat = BoatLocation.LOCAL;
  85. public ActionName curAct;
  86.  
  87. public const int MAX_MONSTER_COUNT = 3;
  88. public const int MAX_MONK_COUNT = 3;
  89.  
  90. //此方法用于剪枝
  91. public bool CanTakeAction(ActionEffection ae)
  92. {
  93. if (boat == ae.boat_to)
  94. return false;
  95.  
  96. int local_move_monster = local_monster + ae.move_monster;
  97. int local_move_monk = local_monk + ae.move_monk;
  98. int remote_move_monster = remote_monster - ae.move_monster;
  99. int remote_move_monk = remote_monk - ae.move_monk;
  100. //数量判断
  101. if (local_move_monster < 0 || local_move_monster > MAX_MONSTER_COUNT)
  102. return false;
  103. if (local_move_monk < 0 || local_move_monk > MAX_MONK_COUNT)
  104. return false;
  105.  
  106. return true;
  107. }
  108.  
  109. //判断当前状态是否为最终状态
  110. public bool IsFinalState()
  111. {
  112. if (remote_monster == MAX_MONSTER_COUNT && remote_monk == MAX_MONK_COUNT)
  113. return true;
  114. return false;
  115. }
  116.  
  117. //判断是否为有效状态
  118. public bool IsValidState()
  119. {
  120. //如果妖怪数量>=和尚数量,则和尚会被吃掉。
  121. if ((local_monk > 0 && local_monster > local_monk) || (remote_monk > 0 && remote_monster > remote_monk))
  122. return false;
  123. return true;
  124. }
  125.  
  126. public override string ToString()
  127. {
  128. string s = string.Format("{0}_{1}_{2}_{3}_{4}", boat, local_monster, local_monk, remote_monster, remote_monk);
  129. return s;
  130. }
  131.  
  132. public ItemState Clone()
  133. {
  134. ItemState state = new ItemState();
  135. state.local_monster = local_monster;
  136. state.local_monk = local_monk;
  137. state.remote_monster = remote_monster;
  138. state.remote_monk = remote_monk;
  139. state.boat = boat;
  140. state.curAct = curAct;
  141.  
  142. return state;
  143. }
  144. }
  145.  
  146. //过河动作列表
  147. private ActionEffection[] actEffect = new ActionEffection[10];
  148.  
  149. private StateStack states = new StateStack();
  150.  
  151. private ItemState last_local_state = null;
  152.  
  153. public AcrossRiver()
  154. {
  155. //初始化10种过河动作
  156. actEffect[0] = new ActionEffection(ActionName.ONE_MONSTER_GO, BoatLocation.REMOTE, -1, 0);
  157. actEffect[1] = new ActionEffection(ActionName.TWO_MONSTER_GO, BoatLocation.REMOTE, -2, 0);
  158. actEffect[2] = new ActionEffection(ActionName.ONE_MONK_GO, BoatLocation.REMOTE, 0, -1);
  159. actEffect[3] = new ActionEffection(ActionName.TWO_MONK_GO, BoatLocation.REMOTE, 0, -2);
  160. actEffect[4] = new ActionEffection(ActionName.ONE_MONSTER_ONE_MONK_GO, BoatLocation.REMOTE, -1, -1);
  161. actEffect[5] = new ActionEffection(ActionName.ONE_MONSTER_BACK, BoatLocation.LOCAL, 1, 0);
  162. actEffect[6] = new ActionEffection(ActionName.TWO_MONSTER_BACK, BoatLocation.LOCAL, 2, 0);
  163. actEffect[7] = new ActionEffection(ActionName.ONE_MONK_BACK, BoatLocation.LOCAL, 0, 1);
  164. actEffect[8] = new ActionEffection(ActionName.TWO_MONK_BACK, BoatLocation.LOCAL, 0, 2);
  165. actEffect[9] = new ActionEffection(ActionName.ONE_MONSTER_ONE_MONK_BACK, BoatLocation.LOCAL, 1, 1);
  166.  
  167. //初始化栈
  168. states.Push(new ItemState());
  169. }
  170.  
  171. public void SearchState()
  172. {
  173. ItemState current = states.Back();
  174. if (null == current)
  175. return;
  176.  
  177. if (current.IsFinalState())
  178. {
  179. states.PrintStack();
  180. return;
  181. }
  182. //尝试用10种动作分别与当前状态组合
  183. for (int i = 0; i < actEffect.Length; i++)
  184. {
  185. SearchStateOnNewAction(current, actEffect[i]);
  186. }
  187. }
  188.  
  189. private void SearchStateOnNewAction(ItemState current, ActionEffection ae)
  190. {
  191. ItemState nextState = MakeActionNewState(current, ae);
  192. if (null != nextState)
  193. {
  194. if (nextState.IsValidState() && !states.IsProcessedState(nextState))
  195. {
  196. states.Push(nextState);
  197. SearchState();
  198. states.Pop();
  199. }
  200. }
  201. }
  202.  
  203. private ItemState MakeActionNewState(ItemState curState, ActionEffection ae)
  204. {
  205. ItemState newState = null;
  206.  
  207. if (null == last_local_state)
  208. {
  209. last_local_state = curState;
  210. }
  211.  
  212. if (curState.CanTakeAction(ae))
  213. {
  214. newState = curState.Clone();
  215. newState.local_monster += ae.move_monster;
  216. newState.local_monk += ae.move_monk;
  217. newState.remote_monster -= ae.move_monster;
  218. newState.remote_monk -= ae.move_monk;
  219. newState.boat = ae.boat_to;
  220. newState.curAct = ae.act;
  221. }
  222.  
  223. return newState;
  224. }
  225.  
  226. /// <summary>
  227. /// 状态栈
  228. /// </summary>
  229. private class StateStack
  230. {
  231. private List<ItemState> list = new List<ItemState>();
  232. private Dictionary<string, bool> dic = new Dictionary<string, bool>();
  233. private int way = 1;
  234.  
  235. public ItemState Back()
  236. {
  237. ItemState state = null;
  238. if (list.Count > 0)
  239. {
  240. state = list[list.Count - 1];
  241. }
  242. return state;
  243. }
  244.  
  245. public void Push(ItemState state)
  246. {
  247. string key = state.ToString();
  248. if (dic.ContainsKey(key))
  249. return;
  250.  
  251. dic.Add(key, true);
  252. list.Add(state);
  253. }
  254.  
  255. public void Pop()
  256. {
  257. if (list.Count > 0)
  258. {
  259. ItemState state = list[list.Count - 1];
  260. list.RemoveAt(list.Count - 1);
  261. dic.Remove(state.ToString());
  262. }
  263. }
  264.  
  265. public void Clear()
  266. {
  267. list.Clear();
  268. dic.Clear();
  269. way = 1;
  270. }
  271.  
  272. //判断是否为已搜索过的状态(即,去重)
  273. public bool IsProcessedState(ItemState state)
  274. {
  275. return dic.ContainsKey(state.ToString());
  276. }
  277.  
  278. public void PrintStack()
  279. {
  280. Console.WriteLine("方案: {0} ({1}步)", way++, list.Count);
  281. ItemState state = null;
  282. for (int i = 0; i < list.Count; i++)
  283. {
  284. state = list[i];
  285. Console.WriteLine("{0} ({1}, {2}, {3}, {4})",
  286. state.curAct, state.local_monster, state.local_monk, state.remote_monster, state.remote_monk);
  287. }
  288. Console.WriteLine("end");
  289. }
  290. }
  291. }

运行效果:

r1.png

r2.png

标签: Algorithms

Powered by emlog  蜀ICP备18021003号-1   sitemap

川公网安备 51019002001593号